Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Current implementation of Keystrokes/Macros is broken... #382

Open
gbdlin opened this issue Aug 16, 2019 · 27 comments
Open

Current implementation of Keystrokes/Macros is broken... #382

gbdlin opened this issue Aug 16, 2019 · 27 comments

Comments

@gbdlin
Copy link

gbdlin commented Aug 16, 2019

Someone at some point did a big mistake by removing keystroke functionality, as you can allegedly achieve the same functionality through macros.

Well... this assumption is very far from being true and here are reasons why:

  1. Macros work only one way (on button press), there are no additional set of keystrokes executed on button release. For that reason, you cannot execute any press and hold keystroke. For example if someone tries to bind shift key directly to one of his mouse buttons, so he can hold it instead of shift on keyboard to write in capitals, it is not possible using macros. Same goes for voice communication, you cannot bind Push To Talk to any mouse button as there is no possibility to say "when I release this mouse button, release my PTT button".
  2. You cannot use media keys or any non-standard keys inside macros. This is a limitation either in Logitech drivers on in Logitech mice. You just cannot save any media key inside macro, it just won't save in memory of your device.
  3. Any keystroke set from windows driver will show up as undefined. Keystrokes are not dynamically converted to macros and for that reason you will just see that particular button was not set.

I know that those issues can be "fixed" somehow by introducing automatic switch between macro and keystroke in background, but more issues will pop up after those fixes. For example, I cannot see any reasonable way to distinguish between those actions, preserving macro-only UX:

  • Press key X and hold it forever, don't execute release action
  • Press key X and release it immediately, even if I'm still holding mouse button
  • Press key X and release it when I'll release mouse button

Best interface to distinguish that is to separate macros from keystrokes.

Another example: to allow media keys to be set, you'll need to allow them in macros, detect that media key is used and switch to keystroke. And what if somebody will use media key in the middle of actual macro? You will prompt him that it is not allowed in this situation? How to explain that?

In my opinion, UI change to macro-only should be reverted immediately.

@bentiss
Copy link
Collaborator

bentiss commented Aug 20, 2019

Someone at some point did a big mistake by removing keystroke functionality, as you can allegedly achieve the same functionality through macros.

As being one of the ones who took this decision, I find this quite offensive.

Well... this assumption is very far from being true and here are reasons why

glad to see some constructive comments at least :)

Macros work only one way (on button press), there are no additional set of keystrokes executed on button release.

isn't that just a problem of macro semantic in libratbag/piper? We could perfectly emulate that behavior given that the definition of a macro is just a libratbag dbus API.

You cannot use media keys or any non-standard keys inside macros

Why is that? We replace on the fly "simple" macros into key bindings, so if the hardware is capable of sending a media key only through a keybinding, you should transparently have that behavior

Any keystroke set from windows driver will show up as undefined

That's a bug in libratbag, keybindings should be represented as macros, and they should be transparently identified and used by the underlying ratbagd daemon.

I know that those issues can be "fixed" somehow by introducing automatic switch between macro and keystroke in background, but more issues will pop up after those fixes.

We implemented that when we removed the keybindings capability. It was working, but now I can see that there is something wrong and the macros are not handled properly on Logitech devices, so that's a libratbag bug.

  • Press key X and hold it forever, don't execute release action

libratbag is capable of doing that by using +KEY_X
(see ratbagctl --help)

  • Press key X and release it immediately, even if I'm still holding mouse button

KEY_X, which is an alias for +KEY_X -KEY_X

  • Press key X and release it when I'll release mouse button

That is one thing we are lacking in the libratbag API. Can you open a bug on libratbag for it?

For example, I cannot see any reasonable way to distinguish between those actions, preserving macro-only UX

-> as shown above, this is just a ui problem for the first 2, and the last one we are probably missing a wait_for_button_release command, and then we would need the piper implementation. of course.

Another example: to allow media keys to be set, you'll need to allow them in macros, detect that media key is used and switch to keystroke. And what if somebody will use media key in the middle of actual macro? You will prompt him that it is not allowed in this situation? How to explain that?

That is the question we always had in libratbag in general, how to make sure the UI is fully compatible with all the devices we have around. Currently piper tries to set the new values, and it hopes ratbagd will apply it or return an error. Unless piper knows about all of the device internals, we can not pre-validate the macro as it is typed.

In my opinion, UI change to macro-only should be reverted immediately.

That is not a UI change, it's a libratbag/ratbagd change, and it seems there are at least 2 bugs:

@adrianocr
Copy link

Ahhhh so it's not only me?

I set up one of my mouse buttons to act as a Gnome application list opener. On my keyboard its [RIGHT] SUPER + A. Piper sets the macro as ↓RIGHTMETA ↓A ↑RIGHTMETA ↑A.

When I click the specified button on my mouse I see that the "Activities" button in the top left of the gnome-shell top panel gets highlighted, but nothing else happens. If I hit the button again, it deselects the gnome-shell activities button. Nothing else happens.

@gbdlin
Copy link
Author

gbdlin commented Jan 14, 2020

Sorry for very late response, but I've just stopped using piper and libratbag at all for a while and forgot about this.

I understand that all the issues can be somehow fixed while maintaining macros and key binds connected together. But IMO this is not worth the trouble as it rises many more, hard to fix problems. Let's see that by example:

Let's have some different mouse models:

  • Mouse A: supports only key binds. Okay, we can just block any attempt of setting complex macros.
  • Mouse B: supports key binds and macros, but you cannot use every key inside macro, subset is limited. It can be of course define that in lib, no problem.
  • Mouse C: supports key binds and macros, but macros will trigger only on press action, no way to define release action. Some definition of this corner case and we're done
  • Many more cases

Doesn't look like much, but... every single mouse in that approach we have to treat as a corner case and build perfect definition of what is supported in macros and what isn't. That's a lot of work and a lot of code to maintain. I know, we need it anyway to support macros, but if we keep those 2 things merged, we also need those corner cases to support simple key binds - feature that is much, much easier in general. Most of the users don't even care as macros, I personally never needed a macro on my mouse. Simple key binds are enough.

So now, if we won't define macros support table for any mouse, we won't even deliver key binds functionality.

Another problem I see is with mouse A in examples above. It can only support key binds. Now you have to force using single key press on button press action and single key release on button release action. If you don't define both, macro should be rejected as not supported. If you try to fix that for user, you will make inconsistent interface between this model and model that supports macros.

I still also think that key binds should be separate as this is IMO basic functionality, where macros are more advanced and designed for people that really need them. Combining them together creates very hard user experience for people that don't need macros, without any improvement for people that do need one and without any improvement (only complications) in code simplicity and feature support.

@alejo9719
Copy link

I have an issue with media keys. Volume up/down works when I set them in the Piper config. Nevertheless, nextsong, play/pause and previoussong don't work even if they're shown as configured when I do it. Once I close and reopen Piper, the key bindings for those are shown as "Unknown" ("Desconocido" in Spanish) instead of their corresponding actions.

imagen

@TheDoctor40
Copy link

Then you're having more luck than me. I have the G8 and G7 buttons on my G502 Lightspeed set to volume using G HUB on Windows. Linux does not detect it however, even though the mouse is in on-board mode. My G502 Proteus Core, which is still supported by Logitech Gaming Software did not have this issue. I could set it using that to volume, put it in on-board mode and the volume would work out of the box in Linux. My workaround is to set the volume in Linux to a specific keyboard combo and then binding that to my Lightspeed. Not sure if I have to set the buttons back when on Windows though, haven't tried it yet.

@FFY00
Copy link
Member

FFY00 commented Apr 27, 2020

That doesn't seem right. If the device is actually in onboard mode and it works on Windows, it should work on Linux.

Can you paste the output of ratbagctl <device> info for that device? What do you see in libinput record?

@alejo9719
Copy link

alejo9719 commented Apr 27, 2020

Then you're having more luck than me. I have the G8 and G7 buttons on my G502 Lightspeed set to volume using G HUB on Windows. Linux does not detect it however, even though the mouse is in on-board mode. My G502 Proteus Core, which is still supported by Logitech Gaming Software did not have this issue. I could set it using that to volume, put it in on-board mode and the volume would work out of the box in Linux. My workaround is to set the volume in Linux to a specific keyboard combo and then binding that to my Lightspeed. Not sure if I have to set the buttons back when on Windows though, haven't tried it yet.

I am using the same workaround for nextsong, play/pause and previoussong. In Windows, I use the Logitech Gaming Software (I've been using it since 2016) to configure my keys and they work flawlessly. My mouse is a G600.

@FFY00
Copy link
Member

FFY00 commented Apr 27, 2020

Is it on onboard memory mode? If it is we should be able to do the same in libratbag.

@TheDoctor40
Copy link

TheDoctor40 commented Apr 27, 2020

That doesn't seem right. If the device is actually in onboard mode and it works on Windows, it should work on Linux.

Can you paste the output of ratbagctl <device> info for that device? What do you see in libinput record?

Sure

Output of ratbagctl <device> info:

hooting-chinchilla - Logitech G502
             Model: usb:046d:407f:0
 Number of Buttons: 11
    Number of Leds: 2
Number of Profiles: 5
Profile 0: (active)
  Name: n/a
  Report Rate: 1000Hz
  Resolutions:
    0: 400dpi
    1: 2000dpi (active) (default)
    2: 0dpi
    3: 0dpi
    4: 0dpi
  Button: 0 is mapped to 'button 1'
  Button: 1 is mapped to 'button 2'
  Button: 2 is mapped to 'button 3'
  Button: 3 is mapped to 'button 4'
  Button: 4 is mapped to 'button 5'
  Button: 5 is mapped to 'resolution-alternate'
  Button: 6 is mapped to macro '↕VOLUMEDOWN'
  Button: 7 is mapped to macro '↕VOLUMEUP'
  Button: 8 is mapped to 'unknown'
  Button: 9 is mapped to 'wheel-right'
  Button: 10 is mapped to 'wheel-left'
  LED: 0, depth: rgb, mode: on, color: 773800
  LED: 1, depth: rgb, mode: on, color: ff6c00
Profile 1: (disabled)
Profile 2: (disabled)
Profile 3: (disabled)
Profile 4: (disabled)

If I run libinput record, pressing the G8 and G7 buttons outputs nothing when they are set up from Windows.

@alejo9719 My first guess was to try Logitech Gaming Software to see if that solves it, but unfortunately the G502 Lightspeed only supports G-Hub. Because of the whole Coronavirus situation I'm back at home with my parents instead of my study apartment so I don't have access to my G502 Proteus Spectrum at the moment.

@FFY00
Copy link
Member

FFY00 commented Apr 27, 2020

Which kernel version are you running?

There is a possibility that your device does not support those key codes. Even it being in onboard mode, the Windows drivers could be doing something in software due to the keys not being supported, please kill the Logitech software and see if they still work.

@TheDoctor40
Copy link

By coincidence I just did a clean install of Ubuntu 20.04 on my machine. My current kernel is 5.4.0-26-generic.

I will switch back to Windows right now to try turning off the software to see what it does and report back after.

@TheDoctor40
Copy link

Update: I logged in to Windows, quit the G-Hub software, and the volume controls still worked.

@FFY00
Copy link
Member

FFY00 commented Apr 27, 2020

Did you make sure it was not running in background?

@TheDoctor40
Copy link

TheDoctor40 commented Apr 27, 2020

Yes. I even checked all the processes in my Task Manager and closed the G-Hub updater service as well, and also all the processes from Logitech Options (I own an MX Master as well). Volume controlls still worked. I even tried on my brother's Windows machine, which doesn't even have any Logitech software installed. Volume still worked there.

I also updated to the latest stable kernel; 5.5.4-050504-generic, to no avail.

@FFY00
Copy link
Member

FFY00 commented Apr 27, 2020

That is weird, can you install hid-tools (available via pip) and run hid-recorder on the device? Something must show up there.

@TheDoctor40
Copy link

I ran hid-recorder and this time got some output when pressing the G8 and G7 buttons. I'll paste the output which I got by running hid-recorder. I only pressed the G8 and G7 buttons, no other ones and I did not move the mouse within that run.

Available devices:
/dev/hidraw0:	UNIW0001:00 093A:1336
/dev/hidraw1:	Logitech USB Receiver
/dev/hidraw2:	Logitech USB Receiver
/dev/hidraw3:	Logitech USB Receiver
/dev/hidraw4:	ITE Tech. Inc. ITE Device(8291)
/dev/hidraw5:	Logitech G502
Select the device event number [0-5]: 5
# Logitech G502
# 0x05, 0x01,                    // Usage Page (Generic Desktop)        0
# 0x09, 0x06,                    // Usage (Keyboard)                    2
# 0xa1, 0x01,                    // Collection (Application)            4
# 0x85, 0x01,                    //  Report ID (1)                      6
# 0x95, 0x08,                    //  Report Count (8)                   8
# 0x75, 0x01,                    //  Report Size (1)                    10
# 0x15, 0x00,                    //  Logical Minimum (0)                12
# 0x25, 0x01,                    //  Logical Maximum (1)                14
# 0x05, 0x07,                    //  Usage Page (Keyboard)              16
# 0x19, 0xe0,                    //  Usage Minimum (224)                18
# 0x29, 0xe7,                    //  Usage Maximum (231)                20
# 0x81, 0x02,                    //  Input (Data,Var,Abs)               22
# 0x95, 0x06,                    //  Report Count (6)                   24
# 0x75, 0x08,                    //  Report Size (8)                    26
# 0x15, 0x00,                    //  Logical Minimum (0)                28
# 0x26, 0xff, 0x00,              //  Logical Maximum (255)              30
# 0x05, 0x07,                    //  Usage Page (Keyboard)              33
# 0x19, 0x00,                    //  Usage Minimum (0)                  35
# 0x2a, 0xff, 0x00,              //  Usage Maximum (255)                37
# 0x81, 0x00,                    //  Input (Data,Arr,Abs)               40
# 0x85, 0x0e,                    //  Report ID (14)                     42
# 0x05, 0x08,                    //  Usage Page (LEDs)                  44
# 0x95, 0x05,                    //  Report Count (5)                   46
# 0x75, 0x01,                    //  Report Size (1)                    48
# 0x15, 0x00,                    //  Logical Minimum (0)                50
# 0x25, 0x01,                    //  Logical Maximum (1)                52
# 0x19, 0x01,                    //  Usage Minimum (1)                  54
# 0x29, 0x05,                    //  Usage Maximum (5)                  56
# 0x91, 0x02,                    //  Output (Data,Var,Abs)              58
# 0x95, 0x01,                    //  Report Count (1)                   60
# 0x75, 0x03,                    //  Report Size (3)                    62
# 0x91, 0x01,                    //  Output (Cnst,Arr,Abs)              64
# 0xc0,                          // End Collection                      66
# 0x05, 0x01,                    // Usage Page (Generic Desktop)        67
# 0x09, 0x02,                    // Usage (Mouse)                       69
# 0xa1, 0x01,                    // Collection (Application)            71
# 0x85, 0x02,                    //  Report ID (2)                      73
# 0x09, 0x01,                    //  Usage (Pointer)                    75
# 0xa1, 0x00,                    //  Collection (Physical)              77
# 0x05, 0x09,                    //   Usage Page (Button)               79
# 0x19, 0x01,                    //   Usage Minimum (1)                 81
# 0x29, 0x10,                    //   Usage Maximum (16)                83
# 0x15, 0x00,                    //   Logical Minimum (0)               85
# 0x25, 0x01,                    //   Logical Maximum (1)               87
# 0x95, 0x10,                    //   Report Count (16)                 89
# 0x75, 0x01,                    //   Report Size (1)                   91
# 0x81, 0x02,                    //   Input (Data,Var,Abs)              93
# 0x05, 0x01,                    //   Usage Page (Generic Desktop)      95
# 0x16, 0x01, 0x80,              //   Logical Minimum (-32767)          97
# 0x26, 0xff, 0x7f,              //   Logical Maximum (32767)           100
# 0x75, 0x10,                    //   Report Size (16)                  103
# 0x95, 0x02,                    //   Report Count (2)                  105
# 0x09, 0x30,                    //   Usage (X)                         107
# 0x09, 0x31,                    //   Usage (Y)                         109
# 0x81, 0x06,                    //   Input (Data,Var,Rel)              111
# 0x15, 0x81,                    //   Logical Minimum (-127)            113
# 0x25, 0x7f,                    //   Logical Maximum (127)             115
# 0x75, 0x08,                    //   Report Size (8)                   117
# 0x95, 0x01,                    //   Report Count (1)                  119
# 0x09, 0x38,                    //   Usage (Wheel)                     121
# 0x81, 0x06,                    //   Input (Data,Var,Rel)              123
# 0x05, 0x0c,                    //   Usage Page (Consumer Devices)     125
# 0x0a, 0x38, 0x02,              //   Usage (AC Pan)                    127
# 0x95, 0x01,                    //   Report Count (1)                  130
# 0x81, 0x06,                    //   Input (Data,Var,Rel)              132
# 0xc0,                          //  End Collection                     134
# 0xc0,                          // End Collection                      135
# 0x06, 0x00, 0xff,              // Usage Page (Vendor Defined Page 1)  136
# 0x09, 0x01,                    // Usage (Vendor Usage 1)              139
# 0xa1, 0x01,                    // Collection (Application)            141
# 0x85, 0x10,                    //  Report ID (16)                     143
# 0x75, 0x08,                    //  Report Size (8)                    145
# 0x95, 0x06,                    //  Report Count (6)                   147
# 0x15, 0x00,                    //  Logical Minimum (0)                149
# 0x26, 0xff, 0x00,              //  Logical Maximum (255)              151
# 0x09, 0x01,                    //  Usage (Vendor Usage 1)             154
# 0x81, 0x00,                    //  Input (Data,Arr,Abs)               156
# 0x09, 0x01,                    //  Usage (Vendor Usage 1)             158
# 0x91, 0x00,                    //  Output (Data,Arr,Abs)              160
# 0xc0,                          // End Collection                      162
# 0x06, 0x00, 0xff,              // Usage Page (Vendor Defined Page 1)  163
# 0x09, 0x02,                    // Usage (Vendor Usage 2)              166
# 0xa1, 0x01,                    // Collection (Application)            168
# 0x85, 0x11,                    //  Report ID (17)                     170
# 0x75, 0x08,                    //  Report Size (8)                    172
# 0x95, 0x13,                    //  Report Count (19)                  174
# 0x15, 0x00,                    //  Logical Minimum (0)                176
# 0x26, 0xff, 0x00,              //  Logical Maximum (255)              178
# 0x09, 0x02,                    //  Usage (Vendor Usage 2)             181
# 0x81, 0x00,                    //  Input (Data,Arr,Abs)               183
# 0x09, 0x02,                    //  Usage (Vendor Usage 2)             185
# 0x91, 0x00,                    //  Output (Data,Arr,Abs)              187
# 0xc0,                          // End Collection                      189
# 0x06, 0x00, 0xff,              // Usage Page (Vendor Defined Page 1)  190
# 0x09, 0x04,                    // Usage (Vendor Usage 0x04)           193
# 0xa1, 0x01,                    // Collection (Application)            195
# 0x85, 0x20,                    //  Report ID (32)                     197
# 0x75, 0x08,                    //  Report Size (8)                    199
# 0x95, 0x0e,                    //  Report Count (14)                  201
# 0x15, 0x00,                    //  Logical Minimum (0)                203
# 0x26, 0xff, 0x00,              //  Logical Maximum (255)              205
# 0x09, 0x41,                    //  Usage (Vendor Usage 0x41)          208
# 0x81, 0x00,                    //  Input (Data,Arr,Abs)               210
# 0x09, 0x41,                    //  Usage (Vendor Usage 0x41)          212
# 0x91, 0x00,                    //  Output (Data,Arr,Abs)              214
# 0x85, 0x21,                    //  Report ID (33)                     216
# 0x95, 0x1f,                    //  Report Count (31)                  218
# 0x15, 0x00,                    //  Logical Minimum (0)                220
# 0x26, 0xff, 0x00,              //  Logical Maximum (255)              222
# 0x09, 0x42,                    //  Usage (Vendor Usage 0x42)          225
# 0x81, 0x00,                    //  Input (Data,Arr,Abs)               227
# 0x09, 0x42,                    //  Usage (Vendor Usage 0x42)          229
# 0x91, 0x00,                    //  Output (Data,Arr,Abs)              231
# 0xc0,                          // End Collection                      233
# 
R: 234 05 01 09 06 a1 01 85 01 95 08 75 01 15 00 25 01 05 07 19 e0 29 e7 81 02 95 06 75 08 15 00 26 ff 00 05 07 19 00 2a ff 00 81 00 85 0e 05 08 95 05 75 01 15 00 25 01 19 01 29 05 91 02 95 01 75 03 91 01 c0 05 01 09 02 a1 01 85 02 09 01 a1 00 05 09 19 01 29 10 15 00 25 01 95 10 75 01 81 02 05 01 16 01 80 26 ff 7f 75 10 95 02 09 30 09 31 81 06 15 81 25 7f 75 08 95 01 09 38 81 06 05 0c 0a 38 02 95 01 81 06 c0 c0 06 00 ff 09 01 a1 01 85 10 75 08 95 06 15 00 26 ff 00 09 01 81 00 09 01 91 00 c0 06 00 ff 09 02 a1 01 85 11 75 08 95 13 15 00 26 ff 00 09 02 81 00 09 02 91 00 c0 06 00 ff 09 04 a1 01 85 20 75 08 95 0e 15 00 26 ff 00 09 41 81 00 09 41 91 00 85 21 95 1f 15 00 26 ff 00 09 42 81 00 09 42 91 00 c0
N: Logitech G502
I: 3 046d 407f
# ReportID: 16 /Vendor Defined Page 1 ['01', '41', '0c', 'b2', '7f', '40'] 
E: 000000.000000 7 10 01 41 0c b2 7f 40
# ReportID: 17 /Vendor Defined Page 1 ['01', '00', '01', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00'] 
E: 000000.009530 20 11 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
# ReportID: 16 /Vendor Defined Page 1 ['01', '41', '0c', 'b2', '7f', '40'] 
E: 000003.262869 7 10 01 41 0c b2 7f 40
# ReportID: 17 /Vendor Defined Page 1 ['01', '00', '01', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00', '00'] 
E: 000003.272886 20 11 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

@FFY00
Copy link
Member

FFY00 commented Apr 27, 2020

What happens when you add the following to /etc/modprobe.d/blacklist.conf and replug the device?

blacklist hid_logitech_hidpp

Do the keys work? Note that libratbag/piper won't be able to access the device.

@TheDoctor40
Copy link

Unfortunately no change. Also, piper can still access the device. I double checked my changes to /etc/modprobe.d/blacklist.conf

@FFY00
Copy link
Member

FFY00 commented Apr 28, 2020

What if you do hid-logitech-hidpp? I might have given you the wrong name.

In the end you should not see the module in lsmod | grep logitech.

@TheDoctor40
Copy link

TheDoctor40 commented Apr 28, 2020

Hmm this is weird. I've tried adding hid-logitech-hidpp as well, still to no effect. When I run lsmod | grep logitech however, hid_logitech_hidpp still shows up. I've even tried copying the output of lsmod directly into the blacklist.conf file. Just to be sure I'll also insert the output of the lsmod command.

gilbert@gilbert-15X882-RTX-2060:~$ lsmod | grep logitech
hid_logitech_hidpp     40960  0
hid_logitech_dj        24576  0
usbhid                 57344  1 hid_logitech_dj
hid                   135168  6 i2c_hid,usbhid,hid_multitouch,hid_generic,hid_logitech_dj,hid_logitech_hidpp

@TheDoctor40
Copy link

In the meantime I've tried rebooting. hid_logitech_hidpp is now no longer showing in lsmod | grep logitech, but still no change and piper can still see the mouse.

@TheDoctor40
Copy link

I got it working now! I blacklisted hid_logitech_dj as well and now the volume is working! Piper can also indeed no longer see the device.

@FFY00
Copy link
Member

FFY00 commented Apr 28, 2020

Ah, right, I was thinking of hid-logitech-dj. You probably had to unload the module (modprobe -r) after blacklisting it, rmeoving the device is not enough.

This is a kernel bug.

@TheDoctor40
Copy link

Ah that explains it. Thanks for the help!

@SterlingButters
Copy link

Don't necessarily want to open a new issue for this question:

Can the RETURN keystroke be bound to a button? Unfortunately trying to assign the keystroke macro just "Accepts" the configuration when RETURN is pressed - any ways around this?

@Fatmice
Copy link

Fatmice commented Aug 15, 2020

How does one go about recording a macro with custom timing for keypresses or combined keys (Ctrl+) and combination of both?

@ledarh

This comment was marked as off-topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants