woodruffw / x_do.cr

Crystal bindings for libxdo (xdotool)
https://woodruffw.github.io/x_do.cr/
MIT License
18 stars 1 forks source link

x_do: Add `keys_raw` #17

Closed phil294 closed 1 year ago

phil294 commented 2 years ago

both for window and global

This adds support for the so far unsupported xdo_send_keysequence_window_list_do, with which you can send fine-tuned modifiers, key codes, delays etc.

phil294 commented 2 years ago

This implementation requires you to pass it the keys in an array though (just like libxdo does). This array creation (heap allocation) is however a bit unnecessary since in most cases, you only want to send a single key up/down combination. Typing a word e.g. wouldn't be passing all characters in a single array, instead you send two events for each letter, a down and an up event. xdo_send_keysequence_window_list_do actually expects a keys: Charcodemap* so passing it the pointer of a single key would work too. Sooo... I guess I can add another overload for single key events, but it might be a bit confusing.

That is, if you even approve of this change in general, it's admittedly a bit exotic.

woodruffw commented 2 years ago

Sooo... I guess I can add another overload for single key events, but it might be a bit confusing.

I think that's a premature optimization for now, unless you've actually noticed allocation as a bottleneck here :slightly_smiling_face:

That is, if you even approve of this change in general, it's admittedly a bit exotic.

I don't mind merging PRs that expose more of libxdo's API surface! We might want to think about a higher-level interface, but this looks reasonable as a starting point.

woodruffw commented 2 years ago

In terms of a higher-level API, it might be nice to have a collection of Charcodemap "builder" APIs, so that you could do things like this:

"a series of keys".to_charcodemap

Not sure how much effort that would take, though.

phil294 commented 2 years ago

I think that's a premature optimization

you're right, it's completely irrelevant. I made some tests. In the end, it doesn't even matter if you use keys or type or keys_raw

 raw 527.47  (  1.90ms) (± 7.29%)  1.57kB/op   1.00× slower
type 528.24  (  1.89ms) (± 9.24%)    0.0B/op   1.00× slower
keys 528.35  (  1.89ms) (± 8.63%)    0.0B/op        fastest
Code ```crystal require "./x_do" require "benchmark" class Xy def char key1 = XDo::LibXDo::Charcodemap.new key1.code = 38 [key1] end @x = XDo.new def raw 10.times do @x.keys_raw char, pressed: true, delay: 0 @x.keys_raw char, pressed: false, delay: 0 end end def type @x.type "aaaaaaaaaa", delay: 0 end def keys 10.times do @x.keys "a", delay: 0 end end end Benchmark.ips do |m| xy = Xy.new m.report("raw") do xy.raw end m.report("type") do xy.type end m.report("keys") do xy.keys end end ```

since the bottleneck seems to be X11 itself anyway.

"a series of keys".to_charcodemap

I don't think this makes a lot of sense. This would return an array of 32 arrays (two for each letter) of size 1, but what do you do with that other than sending it? To get the charcodemap, the code also needs to somehow know the key codes and such, and this is already nicely wrapped by type. I wouldn't know how to reliably look them up - you can use xev manually, or ask XKeysymToKeycode. I'm using @display.keysym_to_keycode from x11-cr. My usecase is sending keys based on keysyms, probably a rather uncommon approach, but for that you need to be able to send the keys to x_do in form of key codes, not strings. Other than that, I'm not sure why charcodemap would be useful.

woodruffw commented 1 year ago

Sorry, I just realized that I totally forgot to merge this -- the changes here look reasonable to me, thank you!