mooz / xkeysnail

Yet another keyboard remapping tool for X environment
890 stars 112 forks source link

Sending modifier key by itself on output side of K function? #158

Closed RedBearAK closed 2 years ago

RedBearAK commented 2 years ago

I've got an application with an unusual keyboard shortcut structure (ONLYOFFICE Desktop Editors). It wants the user to hit the Alt key, then type the appropriate letter from a bunch of yellow tooltips that appear on the window. This is a distinct sequence of separate keystrokes rather than a typical shortcut "combo". You have to release the Alt key before typing the shortcut letter. If you try to do it as a combo nothing happens.

Problem is, it seems to be impossible to get xkeysnail to send a modifier key by itself as part of the output side of a K remap function.

I can sort of understand the issues with allowing the user to remap a single modifier key with no other keystroke on the input side of the K function. That would fundamentally mess with how the keyboard works. But I'm just trying to send out the Alt key keystroke as part of a macro on the output side of the K function. I can't think of any good reason for that not to be allowed.

When I try to use "M" or "Alt" or "Shift-M" without some non-modifier key added within the quotes, xkeysnail either crashes with an attribute error or simply sends the letter "M" or "m" to the app, rather than the desired modifier key (Alt).

I did try to use things like "LM" or "RM" so that it wouldn't just send the letter "M", but those produced errors also.

Is there any way to overcome this problem and do this sequence as an output remap, or will xkeysnail need to be patched to let something like this work?

    K("RC-comma"): [K("M"),K("c"),K("Up"),K("Enter")],       # Open Preferences (Advanced Settings)

"Alt", then the letter "c", then "Up", then "Enter", is what it should do.

joshgoebel commented 2 years ago

No, modifiers can't be used as a "keypress" all on their own. Right now all macro output is in the form of combos which are either:

You can't have just a modifier. I can't think of a reason this wouldn't technically be possible in the future. ACTUALLY - maybe you could make this work now with some elbow grease... try importing Combo (from key) and then making a Combo manually like:

Combo(None, Key.META_RIGHT) # or whatever it's called

And use that for your key instead of K(whatever).

RedBearAK commented 2 years ago

@joshgoebel

Uhhhh, kind of stuck on the "import Combo (from key)" part. What precisely does that mean?

Tried a couple of things with my limited python knowledge, but they didn't work.

Even tried copying the whole Combo class from key.py but I'm pretty sure that's not what you meant.

joshgoebel commented 2 years ago

Yes, that's what I meant. Well import it, not copy it.

from .key import Combo

# later
K("RC-comma"): Combo(None, Key.META_RIGHT) , 
RedBearAK commented 2 years ago

@joshgoebel

That doesn't seem to cause a crash on startup, but I do get the error that ".key" could not be resolved (VS Code, Pylance).

Also doesn't appear to work, either by itself or as part of a macro.

I noticed this app actually has different shortcuts for different parts of the app, and there is no way to compensate for that with just the WM_CLASS, so I don't really think this is worth pursuing. I haven't run into any other application that wants a modifier key used by itself to reveal shortcuts.

joshgoebel commented 2 years ago

Oh sorry, python isn't my first language :-)

# from the example
from xkeysnail.transform import *

So it would be:

from xkeysnail.key import Combo
joshgoebel commented 2 years ago

and there is no way to compensate for that with just the WM_CLASS

There is talk of conditions based on other window properties, but yeah if you're trying to have entirely different maps within a single app... that's a bit of a tall order.

joshgoebel commented 2 years ago

@RedBearAK Does your thumbs up mean you got it working? :)

RedBearAK commented 2 years ago

@joshgoebel

At the time all that meant was that the import syntax finally worked without complaining that it couldn't find the reference.

Now, after messing around for a while I think I've figured out something major that really needs to be fixed with xkeysnail.

The whole Linux world, actually, can't seem to make up it's mind about what the Meta key refers to. From what I remember there was in fact a key in ancient computing times that was actually labeled "Meta". But today, many places in Linux, like KDE shortcuts, refer to the Win/Super key as "Meta". Whereas GNOME seems to refer to the same physical key as "Super".

In xkeysnail, it seems to want to refer to the Windows/Super key as "Meta" in some cases:

    # - Default Mac/Win
    # -- Default Win
    Key.LEFT_ALT: Key.RIGHT_CTRL,   # WinMac
    Key.LEFT_META: Key.LEFT_ALT,    # WinMac
    Key.LEFT_CTRL: Key.LEFT_META,   # WinMac
    Key.RIGHT_ALT: Key.RIGHT_CTRL,  # WinMac - Multi-language (Remove)
    Key.RIGHT_META: Key.RIGHT_ALT,  # WinMac - Multi-language (Remove)
    Key.RIGHT_CTRL: Key.RIGHT_META, # WinMac - Multi-language (Remove)

This part of Kinto config remaps physical Alt to Ctrl, physical Win/Super to Alt, and physical Ctrl to Win/Super (for GUI apps, terminals are slightly different).

But when you are building shortcuts that are based on sending the Alt key to the app, you use M, short for Meta.

define_keymap(re.compile(chromeStr, re.IGNORECASE),{
    K("C-comma"): [K("M-e"), K("s"),K("Enter")],    # Open preferences
    K("RC-q"):              K("M-F4"),              # Quit Chrome(s) browsers with Cmd+Q
    # K("RC-Left"):           K("M-Left"),            # Page nav: Back to prior page in history (conflict with wordwise)
    # K("RC-Right"):          K("M-Right"),           # Page nav: Forward to next page in history (conflict with wordwise)
    K("RC-Left_Brace"):     K("M-Left"),            # Page nav: Back to prior page in history
    K("RC-Right_Brace"):    K("M-Right"),           # Page nav: Forward to next page in history
}, "Chrome Browsers")
# Opera C-F12

All these shortcuts for Chrome start with the Alt key.

There are a couple of shortcuts in Kinto's config that use "Alt" instead of "M", and I'm not sure why, but I seemed to run into some trouble when I tried to use "Alt" in other shortcuts. So I stick with M.

Long story short, this is what will actually send Alt by itself into the app I'm trying to work with:

    K("RC-comma"):              Combo(None, Key.LEFT_ALT),    # Open Preferences (Advanced Settings)

So why is M used as a representation of Alt in K shortcuts? This just causes confusion.

Win/Super is Super, Ctrl is C/LC/RC, Shift is Shift, Alt should be A/LA/RA, but it's Alt or M/LM/RM. Yet in xkeysnail modifier remapping RIGHT_META/LEFT_META clearly refers to the physical Win/Super key, and RIGHT_ALT/LEFT_ALT is Alt.

Argh.

RedBearAK commented 2 years ago

@joshgoebel

So this actually performs the intended shortcut in the Spreadsheet or Presentation portion of the ONLYOFFICE app, to access preferences:

    K("RC-comma"):              [Combo(None, Key.LEFT_ALT),K("c"),K("Up"),K("Enter")],       # Open Preferences (Advanced Settings)
Printing key/action:     Key.LEFT_ALT             Action.PRESS
Printing key/action:     Key.LEFT_ALT             Action.RELEASE
Printing key/action:     Key.RIGHT_CTRL             Action.PRESS
Printing key/action:     Key.RIGHT_CTRL             Action.RELEASE
Printing key/action:     Key.C             Action.PRESS
Printing key/action:     Key.C             Action.RELEASE
Printing key/action:     Key.RIGHT_CTRL             Action.PRESS
Printing key/action:     Key.RIGHT_CTRL             Action.RELEASE
Printing key/action:     Key.UP             Action.PRESS
Printing key/action:     Key.UP             Action.RELEASE
Printing key/action:     Key.RIGHT_CTRL             Action.PRESS
Printing key/action:     Key.RIGHT_CTRL             Action.RELEASE
Printing key/action:     Key.ENTER             Action.PRESS
Printing key/action:     Key.ENTER             Action.RELEASE
Printing key/action:     Key.RIGHT_CTRL             Action.PRESS
Printing key/action:     Key.RIGHT_CTRL             Action.RELEASE
Printing key/action:     Key.RIGHT_CTRL             Action.RELEASE

But the "Document" portion of the app shows "B" instead of "C" for the same function/tooltip, so until the ONLYOFFICE developers can standardize their own internal shortcuts this whole exercise is not very effective. They've chosen a really strange and inconsistent way of doing shortcuts. It's a combined app and all windows, even if they are separated out of the usual tabbed UI, have the same WM_CLASS.

Now, if the patch for WM_NAME ever makes it into mainline Kinto, things will get very interesting.

joshgoebel commented 2 years ago

https://askubuntu.com/questions/19558/what-are-the-meta-super-and-hyper-keys

Meta is definitely not Super. Super most commonly refers to the Windows/Command/Super key. Meta is harder to pin down but Alt is command and the closest thing we got these days.

I do see the consistency issue here but there are a lot of people who know these names... I'm not sure changing it woudl be a net improvement. Long-term it'd be nice to allow people to use aliases for keys though so you could write "Cmd-K" if you wanted, etc...

joshgoebel commented 2 years ago

Ok, I see your point now... though I'd like some feedback from others before we jump into changing it... also any changes here are going to break a LOT of config files, etc...

joshgoebel commented 2 years ago

Now, if the patch for WM_NAME ever makes it into mainline Kinto, things will get very interesting.

I definitely want to make this possible just trying to figure out the best API/approach...

joshgoebel commented 2 years ago

@RedBearAK FYI: You can already use LAlt and RAlt when writing your configs if you wish... it's only in the logging they will still show at LM and RM.

RedBearAK commented 2 years ago

@joshgoebel

From the link (pretty sure I’ve seen that page before):

The Windows key is also sometimes called Meta. E.g. in KDE.

I knew I wasn’t imagining things from my KDE Neon days.

Changing anything at this point would certainly mess with a lot of existing configs, and is therefore undesirable and unlikely to happen. It’s just “super” annoying (pun!) to have the same app referring to two different keys as “Meta”.

Maybe, at best, LEFT/RIGHT_META as a modifier identifier could be deprecated in favor of LEFT/RIGHT_SUPER, with a warning about the deprecation in the output so that it could eventually be removed years down the line with minimal damage to users.

joshgoebel commented 2 years ago

This would be further problematic if the key you wanted to send (by itself) was part of the original combo... as the system would consider it already pressed and not see a need to release it and re-assert it. For that kind of thing we'd need Release("Alt") style commands or some such.

joshgoebel commented 2 years ago

Changing anything at this point would certainly mess with a lot of existing configs, and is therefore undesirable and unlikely to happen. I

So far with my fork I've focused on new API plus backwards compatibility (for the most part), ie existing configs should "just work"... but I did go ahead and change the output names of alt to "Alt" instead of "M"... which is easy to do and doesn't break anything.

So the upgrade recommendation would be for users to use the new Alt moniker in their configs as well. The only annoying thing left is Key.*_META which I'm hesistant to muck with because that naming comes from the kernel... but perhaps we could add an alias....

RedBearAK commented 2 years ago

@joshgoebel

I did go ahead and change the output names of alt to "Alt" instead of "M"

Cool.

So the upgrade recommendation would be for users to use the new Alt moniker in their configs as well.

Wasn't "Alt" already an existing option? I don't understand. Or you mean to avoid using "M" in the config file instead of "Alt"?

The only annoying thing left is Key.*_META which I'm hesistant to muck with because that naming comes from the kernel

Wait, so the actual Linux kernel calls the Win/Super key "META"? This begs for the question to be asked, who is actually wrong about the Win/Super key being "Meta"?

Perhaps it would be prudent to ask what was the historical scan code of Super, Hyper, Alt, Ctrl, and Meta, to see if there is a way to decide which is the most correct way to resolve the confusion.

joshgoebel commented 2 years ago

Or you mean to avoid using "M" in the config file instead of "Alt"?

Yes. But leaving it allows legacy configs to work "as is" (for now).

his begs for the question to be asked, who is actually wrong about the Win/Super key being "Meta"?

Well according to the Linux kernel you'd be right I think. And one could certainly make an argument for the modifiers being renamed Modifier.LEFT_META and Modifier.RIGHT_META and let the users sort out the differences...

With the confusion of meta haivng multiple meanings though I'm a little hesitant to push that direction and think it'd probably be clearer to add Key.SUPER_LEFT and Key.SUPER_RIGHT as aliases and suggest most people just avoid the confusingly ambiguous "meta".

was the historical scan code

Well, first of all none of these are scan codes - that's entirely different - these are the low-level input event codes from Linux. And there are codes for ALT, SHIFT, and CTRL, and META... there is no SUPER or HYPER.

joshgoebel commented 2 years ago

I think I asked before if you'd be interested in alpha testing my fork... if so: https://github.com/joshgoebel/xkeysnail

Related: https://github.com/joshgoebel/xkeysnail/issues/7 https://github.com/joshgoebel/xkeysnail/issues/5

joshgoebel commented 2 years ago

I need to finish splitting my awesome wm config and make it's modifiers easy to change (they are the one thing I don't want the mapper to change - so I need to change them back) - and then I can start my own full-time testing.

RedBearAK commented 2 years ago

@joshgoebel

there are codes for ALT, SHIFT, and CTRL, and META... there is no SUPER or HYPER

Doesn't that basically mean that nothing should actually be called "Super", except on a keyboard that actually has a key labeled "Super"? And that the key we're referring to as Win/Super should actually be "Meta", with no "Super" mentioned anywhere? That's how I'm reading this.

Does current xkeysnail config recognize "Meta/RMeta/LMeta" in shortcuts, or just "M/RM/LM" (which is unfortunately "Alt" at the moment)? How hard would it be to treat "Meta/RMeta/LMeta" as an alternative to "Super/RSuper/LSuper" in your branch, thus aligning with the *_META remap? While still treating "M/RM/LM" as "Alt" to avoid breaking configs?

Does this make any sense from your perspective?

There will of course be the problem of GTK environments referring to the Windows key as "Super" in their own shortcut settings, but one has to wonder why they did that if it clashes with the kernel reference. Sounds like KDE are actually doing things more "correctly". So this would just be the opposite of the existing problem of xkeysnail config not aligning with the KDE way.

joshgoebel commented 2 years ago

Doesn't that basically mean that nothing should actually be called "Super",

As I said, one could indeed argue that. I simply don't agree ATM because (personally) I think that makes things more confusing. So I'm not inclined to go that directly without a lot more input. I think in the Linux community that more often than not by default Super refers to the Win/Apple/Command key... so I think therefore Super is less ambiguous (to most users) than "meta".

I could be persuaded I'm wrong, but more people would have to speak up.

treat "Meta/RMeta/LMeta" ... while still treating "M/RM/LM"

I definitely think that is sub-optimal - as it introduces more confusion on both sides of the mapping table. And if the policy is (for now) "don't push meta" when it goes against that clearly.

joshgoebel commented 2 years ago

xkeysnail config not aligning with the KDE way.

Wait, what is the KDE way again? LOL

RedBearAK commented 2 years ago

@joshgoebel

Wait, what is the KDE way again? LOL

KDE calls the "Windows" key "Meta", just like the Linux kernel reference for the key. So they match, at least. Leading to my argument that maybe that's what it should be called in general.

Whereas GTK/GNOME seems to use "Super" for the same key.

But I think the main thing is to divorce "Meta" from "Alt". Whether you want to use "Super" or "Meta" for the "Windows" key is probably of lesser importance. "Super", at this point, is indeed probably less ambiguous.

joshgoebel commented 2 years ago

But I think the main thing is to divorce "Meta" from "Alt".

Then we're in agreement. We'll see how the adoption of my fork goes before I decide to start introduction painful breaking changes. :-) I assume this stuff is mostly a non-issue for Kinto as they can just patch their kinto.py file to remove M references easily enough.

joshgoebel commented 2 years ago

https://github.com/joshgoebel/keyszer/commit/c73e5b79debfc02c2aeedc64d2d9293a016ee336

My fork now goes all-in on the META naming from top to bottom... we still have all the aliases though, except for the M, RM, and LM which will go away for a while to remove any ambiguity during the transition.

RedBearAK commented 2 years ago

@joshgoebel

Just checking, if I replace all the M/RM/LM references with Alt/RAlt/LAlt in my config file, I should still be able to use the same config file between Kinto's xkeysnail and keyszer, correct?

Or has something else happened that no longer allows that cross-compatibility?

Modifier("R_META", aliases = ["RSuper", "RWin", "RCommand", "RCmd", "RMeta"], key = Key.RIGHT_META)
Modifier("L_META", aliases = ["LSuper", "LWin", "LCommand", "LCmd", "LMeta"], key = Key.LEFT_META)
Modifier("META", aliases = ["Super", "Win", "Command", "Cmd", "Meta"], keys = [Key.LEFT_META, Key.RIGHT_META])

Is there really a good argument for having so many different aliases for the same key? What is the purpose of supporting them all simultaneously? I feel like this will just add to user confusion for people trying to learn how to edit a pre-existing config like Kinto's. "Up to the user which alias to use" seems like a recipe for chaos in documentation and among users discussing shortcuts.

What happened to the idea of ditching "Meta" entirely and just going with "Super"? Then there's just the one mismatch between the kernel reference for the modifier and the reference used in shortcuts.

I feel like a note in the config file and other documentation that "Super" represents the "Windows" key on a PC keyboard and the "Command" key on a Mac, and "Meta" (which is the Windows key) in environments like KDE, would be all that most people would need to understand the situation. The Shift, Ctrl and Alt in contrast are self-explanatory since they actually match the label on the key. Even on Macs the Option key also has "Alt" written on it, and it is often referred to as Option/Alt. The reference to the "special" key from each environment should just be consolidated into "Super", as a cross-environment way of referring to it with a more generic name.

I know "Win" was probably already existing as an alias, but that isn't used anywhere in Kinto's config. It's always "Super".

joshgoebel commented 2 years ago

Just checking, if I replace all the M/RM/LM references with Alt/RAlt/LAlt in my config file, I should still be able to use the same config file between Kinto's xkeysnail and keyszer, correct?

Other than having to rename/remove imports, should be... I'm doing so.

Is there really a good argument for having so many different aliases for the same key?

To allow for whatever naming comes naturally to a person.

What happened to the idea of ditching "Meta" entirely and just going with "Super"?

I'm coming around to thinking "meta is correct" (for different reasons) but you obviously disagree... why should I force you to use Meta if Super is more convenient for you and it's no harder for me?

What is the purpose of supporting them all simultaneously?

It's easy to do and I'm not sure I see the downsides you do - this is just a minor documentation issue - and we need most of the aliases for backwards compatibility anyways.

I know "Win" was probably already existing as an alias, but that isn't used anywhere in Kinto's config. It's always "Super".

Lets not presume that Kinto is the only consumer of this software.

RedBearAK commented 2 years ago

@joshgoebel

I'm coming around to thinking "meta is correct" (for different reasons) but you obviously disagree

No, not at all. I was the one arguing earlier that maybe it was more technically correct because it matches the kernel reference. I would be perfectly fine with ditching Super, Win, and Cmd/Command in favor of just going completely with Meta. Of course that would mean having to change the config file to replace Super with Meta everywhere. But I could even do that on the fly with sed, I think. So, not too much of a big deal.

I just want a situation where everyone could talk about the shortcuts in their config files while using, preferably, a single term for the same conceptual key. But, maybe it's just not going to be a big deal.

Lets not presume that Kinto is the only consumer of this software.

All I meant by that was that when I was new to Kinto I didn't have to struggle through a config file that was using both Super and Win to refer to the same key, which would have added to my initial confusion for how to work with the existing shortcuts and make new ones. Luckily Ben decided on Super and stuck with it. That's why all this discussion about using numerous aliases to refer to the same key is kind of bothering me. This is just my perspective.

joshgoebel commented 2 years ago

when I was new to Kinto I didn't have to struggle through a config file that was using both Super and Win to refer to the same key

And you did that despite Ben having plenty of aliases to choose from - that's not new, and it has not presented a real problem in the past. If we have Win we should have Cmd for parity, and meta was ambiguous, so that's been remedied.

If someone wants a clean config file it's up to them to make it so. This is Python, people can do anything - use any aliases they want... we can't stop them... and on top of that breaking backward compatibility... there was a good reason to with Meta, there isn't a good reason for these others.

joshgoebel commented 2 years ago

maybe you could make this work now with some elbow grease... try importing Combo

Actually you can just map to keys directly, it works out of the box:

keymap(
   "Ctrl-Alt-a": Key.LEFT_META
)

There may be glitches with how output handles this though as it doesn't look like it expects combos to be passed singularly... I'd wager in some cases you could wind up with some weird double presses if you mapped things just right, but likely works in most cases.

joshgoebel commented 2 years ago

@RedBearAK Doesn't my last answer close out this issue?

RedBearAK commented 2 years ago

@joshgoebel

Doesn't my last answer close out this issue?

Probably, but I kind of gave up on even trying to do anything with that app, due to their inconsistency even between the different modules of what is essentially a single tabbed-UI application. They really need to rethink how they are doing shortcuts. I would classify what they are doing as the "Fisher Price" method. Easy enough for a child to follow the visible tooltip prompts on the screen, but no advanced level for adults to graduate to using for faster access.

I can confirm that the shortened form seems to work fine in a macro, which is the way I was trying to use it. Just removed the Combo and None around it.

    K("RC-comma"):              [Key.LEFT_ALT,K("c"),K("Up"),K("Enter")],       # Open Preferences (Advanced Settings)

So I'll close this out. Thanks for all your assistance finding a solution. Maybe there's a terminal app that can use this. I haven't encountered any other GUI app that wants this kind of interaction with a sole modifier key, and refuses to respond to combos. But you never know.