enigo icon indicating copy to clipboard operation
enigo copied to clipboard

Held keys do not repeat

Open haata opened this issue 4 years ago • 1 comments

Describe the bug examples/key.rs Holds the a key for 1 second. On Windows and macOS the key only types/prints once. (I've been looking through the macOS API for a way to do this; haven't found one. Still need to go through winapi. It's definitely possible with X11)

To Reproduce Run key.rs example, increase timeout to 5 seconds if your OS settings are set for a slow repeat rate start.

Expected behavior The most recently held key should repeat after an OS (or internal) hold-off time and at a repeat rate interval defined by either the OS (or internal).

Environment (please complete the following information):

  • OS: Windows, macOS (haven't tested X11, but I've written code that does is correctly https://github.com/hid-io/hid-io-core/blob/async/src/module/displayserver/x11.rs)
  • Rust 1.49.0-nightly (a601302ff 2020-11-06)
  • Library Version 43a016f36939a59e1f1874e07bf057d08c31913e

Additional context I think this may be a limitation of the the text input APIs on macOS (and possibly Windows). X11 is composed through fake keypresses (I dynamically assign unicode to unused keycodes and then release them afterwards if the UTF-8 symbol isn't already in the layout). My goal is a bit different than automation, I'm actually writing a Unicode plugin/driver for a programmable keyboard such that the keyboard can map a specific UTF-8 symbol (or string of text) to a key which is then sent to the host and outputted through a daemon of sorts. Since keys can be held, repeating the keys just like standard keypresses is rather important. Latency is also rather important so I have to make sure there's no notable different between UTF-8 symbols and normal keypresses (how they are handled in things like games will probably be "there be dragons", this is mostly for general text use).

(worst case I can emulate it with some thread scheduling and querying of OS timings) (I also have to get around to Wayland, so I'll share my findings once I give it a good try).

haata avatar Nov 07 '20 05:11 haata

From what I can tell on the macOS side of things, you'll need to generate multiple key down events if you want the key to repeat. For repeated key downs, you should increment kCGKeyboardEventAutorepeat each time there's a repeat. So 0 for the first key down, then 1, then 2, for each repeated key down. Then finally a single key up.

That might look something like this. If you call key_click_4 with 42, you'll get 4 backslashes. If you call it with 14, you'll get a single e and the accent menu.

use core_graphics::event::{CGEvent, CGEventTapLocation, CGKeyCode, EventField};

impl Enigo {
    fn key_event_repeat(&mut self, key: CGKeyCode, repeat: i64, down: bool) {
        let event = CGEvent::new_keyboard_event(self.event_source.clone(), key, down).unwrap();
        event.set_integer_value_field(EventField::KEYBOARD_EVENT_AUTOREPEAT, repeat);
        event.post(CGEventTapLocation::HID);
    }
    
    // This doesn't work if you create the events too close together, hence the delays.
    pub fn key_click_4(&mut self, key: CGKeyCode) {
        self.key_event_repeat(key, 0, true);
        std::thread::sleep(std::time::Duration::from_millis(20));
        self.key_event_repeat(key, 1, true);
        std::thread::sleep(std::time::Duration::from_millis(20));
        self.key_event_repeat(key, 2, true);
        std::thread::sleep(std::time::Duration::from_millis(20));
        self.key_event_repeat(key, 3, true);
        std::thread::sleep(std::time::Duration::from_millis(20));
        self.key_event_repeat(key, 0, false);
    }
}

This of course means that it's up to you to do the timing logic to work out when a key repeat is necessary. I have no idea what you'll have to do for the other platforms.

Also, for most keys it seems like key repeat is disabled. See this thread. Holding down some letters like A or E will show the accent menu instead of repeating. Even though only a handful of keys have an accent menu, they've disabled key repeat for all letters.

indianakernick avatar Jan 27 '21 02:01 indianakernick