RedBearAK / toshy

Keymapper config to make Linux work like a 'Tosh!
https://toshy.app
GNU General Public License v3.0
314 stars 16 forks source link

(Enh) CapsLock to Escape on tap or Hyper when held down #388

Open leejoramo-d51 opened 5 days ago

leejoramo-d51 commented 5 days ago

Is your feature request related to a problem? Please describe.

This is a new feature, not related to a problem.

Describe the solution you'd like

I would like to make my CapsLock work as follows:

I have used this on macOS for over 10 years based on the original article A Modern Space Cadet : Hyper Key and Brett Terpstra's implementations

Note: my version of this is a little different in that I do not include the shift key as part of the hyper key but allow it to be added by holding down the actual shift key.

Describe alternatives you've considered

I have tried read through the keyszer documentation and the toshy_config.py file to make this work, but I am not understanding how to make one key press act as multiple other keys.

Additional context None

RedBearAK commented 5 days ago

@leejoramo-d51

It's my current understanding of the modmapping capabilities of the keymapper that it is only designed to change the identity of a single key to another single key. It might theoretically be possible to update the code to handle macros of multiple held keys, but I'm not sure how easily I could do that myself. I added all the Wayland stuff to my fork of the keymapper, but of course I had nothing to do with writing the rest of it (other than a couple of tweaks).

I know the keyszer dev talked about having a Hyper key in his setup, but I'm not sure exactly how he implemented that, or what his Hyper remaps onto. I just opened an issue over there to see what he says about how he does that.

I suspect that at the moment what would need to be done is to create the modifier (I think it can be done from the config file, but I'll have to look into exactly how) and modmap it onto something innocuous like F19. Then a keymap like the "general" keymap would be able to remap F19+[whatever] onto Ctrl+Super+Alt+[whatever].

So I guess a starter question may be how many different Hyper shortcut combos you use.

RedBearAK commented 5 days ago

@leejoramo-d51

This is kind of funky, and I'm not sure I understand why it is working this way. I've never really tried to mess around much with multipurpose_modmap(). There's a multipurpose timeout setting at the beginning of the config file that goes along with how those work, but I had thought that wasn't really something that needed to be tweaked. I thought that when you held a multi-modmapped key and combined it with another key, the "held" part of the modmap would immediately be used, instead of the "tapped" or "momentary" part of the modmap. But in my testing I have to bring the timeout down to something very short, in order to use the key as both Escape and the Hyper modifier effectively. And I have to make sure I hold the key past the timeout in order for the Hyper+key combo to work.

Anyway, this is a basically effective setup I have at the moment.

###################################################################################################
###  SLICE_MARK_START: keymapper_api  ###  EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE

# Keymapper-specific config settings - REMOVE OR SET TO DEFAULTS FOR DISTRIBUTION
dump_diagnostics_key(Key.F15)   # default key: F15
emergency_eject_key(Key.F16)    # default key: F16

timeouts(
    multipurpose        = 0.2,        # default: 1 sec
    suspend             = 0.1,        # default: 1 sec, try 0.1 sec for touchpads/trackpads
)

# Delays often needed for Wayland and/or virtual machines or slow systems
throttle_delays(
    key_pre_delay_ms    = 12,      # default: 0 ms, range: 0-150 ms, suggested: 1-50 ms
    key_post_delay_ms   = 18,      # default: 0 ms, range: 0-150 ms, suggested: 1-100 ms
)

devices_api(
    # Only the specified devices will be "grabbed" and watched for during 
    # device connections/disconnections. 
    only_devices = [
        # 'Example Disconnected Keyboard',
        # 'Example Connected Keyboard',
    ]
)

# Create a new Hyper modifier key alias on F19
Modifier("HYPER", aliases=["Hyper"], key=Key.F19)

# Physical CapsLock is Escape (when tapped) and F19 (when held with other key like modifier)
multipurpose_modmap("CapsLock is Esc and F19", {
    Key.CAPSLOCK: [Key.ESC, Key.F19],
}, when = lambda ctx:
    matchProps(not_clas=remoteStr)(ctx)
)

###  SLICE_MARK_END: keymapper_api  ###  EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE
###################################################################################################
###################################################################################################
###  SLICE_MARK_START: user_apps  ###  EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE

keymap("Testing Hyper modifier", {
    C("Hyper-Space"):           [ST("You pressed Hyper+Space"), C("Enter"), C("Enter")],
}, when = lambda ctx:
    cnfg.screen_has_focus and
    matchProps(not_clas=remoteStr)(ctx)
)

###  SLICE_MARK_END: user_apps  ###  EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE
###################################################################################################

That 0.1 second delay (Edit: changed to 0.2, seems to work better) still means you have to be pretty deliberate on holding the "Hyper" key before completing the shortcut, but any shorter and it becomes very difficult to use the "momentary" function of the modmap. This behavior doesn't make much sense, but I'm not sure what I'm doing wrong that might cause it to work this way.

Unless it's the throttle delay. 🤔

RedBearAK commented 5 days ago

@leejoramo-d51

Unfortunately things seem to go quite wrong when trying to combine Shift with the "held" function of the multi-modmap. It's not just that the shortcut won't work, it will stop the original shortcut from working (the one without Shift), and seems to put the keymapper into a weird state until it gets restarted.

Everything is much easier with a normal modmap, but you'd have to give up trying to use the same key as Escape when tapped.

# Create a new Hyper modifier key alias on F19
Modifier("HYPER", aliases=["Hyper"], key=Key.F19)

# Physical CapsLock is F19
modmap("CapsLock is F19", {
    Key.CAPSLOCK: Key.F19,
}, when = lambda ctx:
    matchProps(not_clas=remoteStr)(ctx)
)
keymap("Testing Hyper modifier", {
    C("Hyper-Space"):           [ST("You pressed Hyper+Space"), C("Enter"), C("Enter")],
    C("Hyper-Shift-Space"):     [ST("You pressed Hyper+Shift+Space"), C("Enter"), C("Enter")],
}, when = lambda ctx:
    cnfg.screen_has_focus and
    matchProps(not_clas=remoteStr)(ctx)
)

Without trying to rewrite parts of the keymapper that I don't understand, I'm not sure if it can really do any better than this.

I'll try to take another look tomorrow.

leejoramo-d51 commented 5 days ago

Thanks for looking into this for me. After writing that feature request, I came down with COVID so I am not at my work computer to try out your work. I will do so once I get back.

RedBearAK commented 4 days ago

Rest up and stay hydrated. 👍🏽