koekeishiya / skhd

Simple hotkey daemon for macOS
MIT License
6.05k stars 204 forks source link

[feature request] synthesizing multiple hotkeys per instance of skhd #128

Open patrickhpan opened 4 years ago

patrickhpan commented 4 years ago

It would be great for skhd to accept multiple -k or -t options to allow synthesizing keypresses many times per one execution of skhd.

Usecase: I'm attempting to make a vim-like mode using skhd and an external program. To run commands such as "20b", I'd need to synthesize "alt - left" 20 times in a row. Running something like for i in $(seq 1 20); skhd -k "alt - left" leads to considerable lag, as starting skhd 20 times incurs significant overhead.

pmilosev commented 4 years ago

Until this is implemented you might want to try cliclick: https://github.com/BlueM/cliclick

However, while it is probably less resource hungry (as it doesn't spawn new processes) the effective time might be even slower:

~ ❯ time cliclick kd:alt $(for i in $(seq 1 200); printf "kp:arrow-left ") ku:alt
0.08s user 0.03s system 0% cpu 26.077 total
~ ❯ time (for i in $(seq 1 200); skhd -k "alt - left")
3.09s user 2.52s system 54% cpu 10.312 total

I'm not sure if you can get much better than that without risking keys not to get registered. The reason 20b is fast in vim is as it controls the buffer and jumps instantly - if you just hold b down on your keyboard it will probably be as slow if not slower. The default (and minimum) delay between events in cliclick is 20ms.

BTW, I found this issue looking around if anyone have implemented vim emulation in skhd. I would appreciate if you can share your work.

patrickhpan commented 4 years ago

I tried cliclick and indeed ran into the issues you mentioned - events seem to be throttled quite a bit.

My pull request #129 modifies the argument parser for skhd so that it accepts sequential -k <keycode> arguments, instead of exiting after the first -k detected. This allows the user to specify -k "alt - left" -k "alt - left", in which both will be executed immediately and sequentially. This seems to work with quite large arguments, like 100 shift - alt - rights followed by a cmd - x (generated by my vim emulation of v100wd), which in my experience deletes 100 words, no more, no less. Check this streamable to see it in action.

My vim emulation is broken and messy, but you can get a general gist for how it works here.

pmilosev commented 4 years ago

Even without the external tools, I am interested in your pull request. E.g. currently in my skhdrc I have things like:

mode_visual < shift - y         : \
    skhd -k 'i' && sleep 0.1   && \
    skhd -k 'alt - down'       && \
    skhd -k 'alt + shift - up' && \
    skhd -k 'cmd - c'          && \
    skhd -k 'escape'

It would be nice not to spawn several processes while doing so. BTW @patrickhpan is there significant performance improvement with your change ?

pmilosev commented 4 years ago

OK, I checked out @patrickhpan fork and measured the performance difference:

time ./bin/skhd -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a -k a
0.03s user 0.02s system 48% cpu 0.091 total

vs.

time (skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;  skhd -k a ;)
1.76s user 1.44s system 52% cpu 6.062 total

I think I will go with your fork until this is integrated here ;)

koekeishiya commented 4 years ago

Having to launch a new process in the first place was a stupid decision that is the result of me previously not wanting to require the use of IPC mechanisms in the main daemon.

daniels commented 2 years ago

instead of exiting after the first -k detected

If this is indeed the current behaviour maybe the syntax for this suggestion could be skhd -k keysym [keysym ...]. It would make it even nicer to write and especially read.

Here's an example from my current config in the three variants:

skhd -k 'escape'; skhd -k 'ctrl - right'; skhd -k 'hyper - space'

skhd -k 'escape' -k 'ctrl - right' -k 'hyper - space'

skhd -k 'escape' 'ctrl - right' 'hyper - space'