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

macOS: Remove all sleeps and add one when the Enigo struct is dropped #329

Merged
merged 1 commit into from
Oct 27, 2024

Conversation

pentamassiv
Copy link
Collaborator

@pentamassiv pentamassiv commented Sep 11, 2024

It looks like all pending events get ignored when the program terminates. It seems like the sleeps were only needed so that the OS had enough time to handle all events before the struct gets dropped. Sleeps during the execution are much more annoying then at the end of the program, so I just added a sleep of two seconds when Enigo gets dropped. That is more than enough for most cases.

In #105 indianakernick mentioned, that for him a sleep is required for modifiers to work. To avoid the sleep, the EventFlags get manually set.

If this works, it makes no sense to offer a user to change a delay on macOS, so the setting and related functions were removed.

This is a big change and needs extensive testing to make sure it always works. Ideally we would also get rid of the sleep in the Drop trait, but so far I found no way to check if all input was simulated.

Fixes #105
Fixes #182
Fixes #163

@pentamassiv pentamassiv force-pushed the macos_no_sleep branch 8 times, most recently from b82c019 to 5d3ffc7 Compare October 12, 2024 15:43
@pentamassiv
Copy link
Collaborator Author

This might also fix #163

@pentamassiv pentamassiv force-pushed the macos_no_sleep branch 2 times, most recently from 8158cab to 25e8c25 Compare October 24, 2024 21:06
@pentamassiv
Copy link
Collaborator Author

pentamassiv commented Oct 24, 2024

I confirmed that it fixes #163 and #182.

Remaining issues:

  • Key::Unicode('🔥') stopped working <- The problem is also present on main
  • Key::Launchpad has no effect

@pentamassiv pentamassiv force-pushed the macos_no_sleep branch 3 times, most recently from 1ead76d to 787357d Compare October 26, 2024 12:12
@pentamassiv
Copy link
Collaborator Author

There are more changes needed. I observed the flags that were set previously and noticed a few differences. Flags also get set when you don't expect it and some of them don't get removed when the key is released again. To do that, I took commit e06beb3 and changed the keyboard.rs example to this code:

use enigo::{
    Direction::{Click, Release},
    Enigo, Keyboard, Settings,
};
use std::time::Duration;

fn main() {
    env_logger::init();

    std::thread::sleep(Duration::from_secs(3));
    for i in 0x00..0xb7 {
        let mut enigo = Enigo::new(&Settings::default()).unwrap();
        enigo.raw(i, Release).unwrap();
        enigo.raw(i, Click).unwrap();
        println!();
    }
}

I also made changes to the src/macos/macos_impl.rs file:

diff --git a/src/macos/macos_impl.rs b/src/macos/macos_impl.rs
index b15513a..25a4b26 100644
--- a/src/macos/macos_impl.rs
+++ b/src/macos/macos_impl.rs
@@ -121,6 +121,7 @@ impl Mouse for Enigo {
                 self.event_source_user_data,
             );
             event.set_flags(CGEventFlags::CGEventFlagNonCoalesced);
+            println!("flags: {:?}", event.get_flags());
             event.post(CGEventTapLocation::HID);
         }
         if direction == Direction::Click || direction == Direction::Release {
@@ -152,6 +153,7 @@ impl Mouse for Enigo {
                 self.event_source_user_data,
             );
             event.set_flags(CGEventFlags::CGEventFlagNonCoalesced);
+            println!("flags: {:?}", event.get_flags());
             event.post(CGEventTapLocation::HID);
         }
         Ok(())
@@ -202,6 +204,7 @@ impl Mouse for Enigo {
             self.event_source_user_data,
         );
         event.set_flags(CGEventFlags::CGEventFlagNonCoalesced);
+        println!("flags: {:?}", event.get_flags());
         event.post(CGEventTapLocation::HID);
         Ok(())
     }
@@ -230,6 +233,7 @@ impl Mouse for Enigo {
             self.event_source_user_data,
         );
         event.set_flags(CGEventFlags::CGEventFlagNonCoalesced);
+        println!("flags: {:?}", event.get_flags());
         event.post(CGEventTapLocation::HID);
         Ok(())
     }
@@ -310,6 +314,7 @@ impl Keyboard for Enigo {
                 EventField::EVENT_SOURCE_USER_DATA,
                 self.event_source_user_data,
             );
+            println!("flags: {:?}", event.get_flags());
             event.post(CGEventTapLocation::HID);
         }
         thread::sleep(Duration::from_millis(2));
@@ -444,6 +449,21 @@ impl Keyboard for Enigo {
                 EventField::EVENT_SOURCE_USER_DATA,
                 self.event_source_user_data,
             );
+            println!(
+                "{:#04x} => {:?}, // {:?} ",
+                keycode,
+                event.get_flags(),
+                keycode,
+            );
+            /* assert_eq!(
+                event.get_flags(),
+                CGEventFlags::CGEventFlagHelp
+                    | CGEventFlags::CGEventFlagSecondaryFn
+                    | CGEventFlags::CGEventFlagNumericPad
+                    | CGEventFlags::from_bits_retain(0x2000_0000),
+                "keycode with other flags: {:#04x}",
+                keycode
+            ); */
             event.post(CGEventTapLocation::HID);
         }
 
@@ -460,6 +480,15 @@ impl Keyboard for Enigo {
                 EventField::EVENT_SOURCE_USER_DATA,
                 self.event_source_user_data,
             );
+            println!(
+                "{:#04x} => {:?}, // {:?} ",
+                keycode,
+                event.get_flags(),
+                keycode,
+            );
ain(0x2000_0000) {
+                println!("sticky keycode: found!");
+            }
             event.post(CGEventTapLocation::HID);
         }
 
@@ -598,6 +627,7 @@ impl Enigo {
                     EventField::EVENT_SOURCE_USER_DATA,
                     self.event_source_user_data,
                 );
+                println!("flags: {:?}", cg_event.get_flags());
                 cg_event.post(CGEventTapLocation::HID);
             } else {
                 return Err(InputError::Simulate(
@@ -627,6 +657,7 @@ impl Enigo {
                     EventField::EVENT_SOURCE_USER_DATA,
                     self.event_source_user_data,
                 );
+                println!("flags: {:?}", cg_event.get_flags());
                 cg_event.post(CGEventTapLocation::HID);
             } else {
                 return Err(InputError::Simulate(

The output is this:

Release and then click each key

0x00 => CGEventFlags(0x20000000), // 0 
0x00 => CGEventFlags(0x20000000), // 0 
0x00 => CGEventFlags(0x20000000), // 0 

0x01 => CGEventFlags(0x20000000), // 1 
0x01 => CGEventFlags(0x20000000), // 1 
0x01 => CGEventFlags(0x20000000), // 1 

0x02 => CGEventFlags(0x20000000), // 2 
0x02 => CGEventFlags(0x20000000), // 2 
0x02 => CGEventFlags(0x20000000), // 2 

0x03 => CGEventFlags(0x20000000), // 3 
0x03 => CGEventFlags(0x20000000), // 3 
0x03 => CGEventFlags(0x20000000), // 3 

0x04 => CGEventFlags(0x20000000), // 4 
0x04 => CGEventFlags(0x20000000), // 4 
0x04 => CGEventFlags(0x20000000), // 4 

0x05 => CGEventFlags(0x20000000), // 5 
0x05 => CGEventFlags(0x20000000), // 5 
0x05 => CGEventFlags(0x20000000), // 5 

0x06 => CGEventFlags(0x20000000), // 6 
0x06 => CGEventFlags(0x20000000), // 6 
0x06 => CGEventFlags(0x20000000), // 6 

0x07 => CGEventFlags(0x20000000), // 7 
0x07 => CGEventFlags(0x20000000), // 7 
0x07 => CGEventFlags(0x20000000), // 7 

0x08 => CGEventFlags(0x20000000), // 8 
0x08 => CGEventFlags(0x20000000), // 8 
0x08 => CGEventFlags(0x20000000), // 8 

0x09 => CGEventFlags(0x20000000), // 9 
0x09 => CGEventFlags(0x20000000), // 9 
0x09 => CGEventFlags(0x20000000), // 9 

0x0a => CGEventFlags(0x20000000), // 10 
0x0a => CGEventFlags(0x20000000), // 10 
0x0a => CGEventFlags(0x20000000), // 10 

0x0b => CGEventFlags(0x20000000), // 11 
0x0b => CGEventFlags(0x20000000), // 11 
0x0b => CGEventFlags(0x20000000), // 11 

0x0c => CGEventFlags(0x20000000), // 12 
0x0c => CGEventFlags(0x20000000), // 12 
0x0c => CGEventFlags(0x20000000), // 12 

0x0d => CGEventFlags(0x20000000), // 13 
0x0d => CGEventFlags(0x20000000), // 13 
0x0d => CGEventFlags(0x20000000), // 13 

0x0e => CGEventFlags(0x20000000), // 14 
0x0e => CGEventFlags(0x20000000), // 14 
0x0e => CGEventFlags(0x20000000), // 14 

0x0f => CGEventFlags(0x20000000), // 15 
0x0f => CGEventFlags(0x20000000), // 15 
0x0f => CGEventFlags(0x20000000), // 15 

0x10 => CGEventFlags(0x20000000), // 16 
0x10 => CGEventFlags(0x20000000), // 16 
0x10 => CGEventFlags(0x20000000), // 16 

0x11 => CGEventFlags(0x20000000), // 17 
0x11 => CGEventFlags(0x20000000), // 17 
0x11 => CGEventFlags(0x20000000), // 17 

0x12 => CGEventFlags(0x20000000), // 18 
0x12 => CGEventFlags(0x20000000), // 18 
0x12 => CGEventFlags(0x20000000), // 18 

0x13 => CGEventFlags(0x20000000), // 19 
0x13 => CGEventFlags(0x20000000), // 19 
0x13 => CGEventFlags(0x20000000), // 19 

0x14 => CGEventFlags(0x20000000), // 20 
0x14 => CGEventFlags(0x20000000), // 20 
0x14 => CGEventFlags(0x20000000), // 20 

0x15 => CGEventFlags(0x20000000), // 21 
0x15 => CGEventFlags(0x20000000), // 21 
0x15 => CGEventFlags(0x20000000), // 21 

0x16 => CGEventFlags(0x20000000), // 22 
0x16 => CGEventFlags(0x20000000), // 22 
0x16 => CGEventFlags(0x20000000), // 22 

0x17 => CGEventFlags(0x20000000), // 23 
0x17 => CGEventFlags(0x20000000), // 23 
0x17 => CGEventFlags(0x20000000), // 23 

0x18 => CGEventFlags(0x20000000), // 24 
0x18 => CGEventFlags(0x20000000), // 24 
0x18 => CGEventFlags(0x20000000), // 24 

0x19 => CGEventFlags(0x20000000), // 25 
0x19 => CGEventFlags(0x20000000), // 25 
0x19 => CGEventFlags(0x20000000), // 25 

0x1a => CGEventFlags(0x20000000), // 26 
0x1a => CGEventFlags(0x20000000), // 26 
0x1a => CGEventFlags(0x20000000), // 26 

0x1b => CGEventFlags(0x20000000), // 27 
0x1b => CGEventFlags(0x20000000), // 27 
0x1b => CGEventFlags(0x20000000), // 27 

0x1c => CGEventFlags(0x20000000), // 28 
0x1c => CGEventFlags(0x20000000), // 28 
0x1c => CGEventFlags(0x20000000), // 28 

0x1d => CGEventFlags(0x20000000), // 29 
0x1d => CGEventFlags(0x20000000), // 29 
0x1d => CGEventFlags(0x20000000), // 29 

0x1e => CGEventFlags(0x20000000), // 30 
0x1e => CGEventFlags(0x20000000), // 30 
0x1e => CGEventFlags(0x20000000), // 30 

0x1f => CGEventFlags(0x20000000), // 31 
0x1f => CGEventFlags(0x20000000), // 31 
0x1f => CGEventFlags(0x20000000), // 31 

0x20 => CGEventFlags(0x20000000), // 32 
0x20 => CGEventFlags(0x20000000), // 32 
0x20 => CGEventFlags(0x20000000), // 32 

0x21 => CGEventFlags(0x20000000), // 33 
0x21 => CGEventFlags(0x20000000), // 33 
0x21 => CGEventFlags(0x20000000), // 33 

0x22 => CGEventFlags(0x20000000), // 34 
0x22 => CGEventFlags(0x20000000), // 34 
0x22 => CGEventFlags(0x20000000), // 34 

0x23 => CGEventFlags(0x20000000), // 35 
0x23 => CGEventFlags(0x20000000), // 35 
0x23 => CGEventFlags(0x20000000), // 35 

0x24 => CGEventFlags(0x20000000), // 36 
0x24 => CGEventFlags(0x20000000), // 36 
0x24 => CGEventFlags(0x20000000), // 36 

0x25 => CGEventFlags(0x20000000), // 37 
0x25 => CGEventFlags(0x20000000), // 37 
0x25 => CGEventFlags(0x20000000), // 37 

0x26 => CGEventFlags(0x20000000), // 38 
0x26 => CGEventFlags(0x20000000), // 38 
0x26 => CGEventFlags(0x20000000), // 38 

0x27 => CGEventFlags(0x20000000), // 39 
0x27 => CGEventFlags(0x20000000), // 39 
0x27 => CGEventFlags(0x20000000), // 39 

0x28 => CGEventFlags(0x20000000), // 40 
0x28 => CGEventFlags(0x20000000), // 40 
0x28 => CGEventFlags(0x20000000), // 40 

0x29 => CGEventFlags(0x20000000), // 41 
0x29 => CGEventFlags(0x20000000), // 41 
0x29 => CGEventFlags(0x20000000), // 41 

0x2a => CGEventFlags(0x20000000), // 42 
0x2a => CGEventFlags(0x20000000), // 42 
0x2a => CGEventFlags(0x20000000), // 42 

0x2b => CGEventFlags(0x20000000), // 43 
0x2b => CGEventFlags(0x20000000), // 43 
0x2b => CGEventFlags(0x20000000), // 43 

0x2c => CGEventFlags(0x20000000), // 44 
0x2c => CGEventFlags(0x20000000), // 44 
0x2c => CGEventFlags(0x20000000), // 44 

0x2d => CGEventFlags(0x20000000), // 45 
0x2d => CGEventFlags(0x20000000), // 45 
0x2d => CGEventFlags(0x20000000), // 45 

0x2e => CGEventFlags(0x20000000), // 46 
0x2e => CGEventFlags(0x20000000), // 46 
0x2e => CGEventFlags(0x20000000), // 46 

0x2f => CGEventFlags(0x20000000), // 47 
0x2f => CGEventFlags(0x20000000), // 47 
0x2f => CGEventFlags(0x20000000), // 47 

0x30 => CGEventFlags(0x20000000), // 48 
0x30 => CGEventFlags(0x20000000), // 48 
0x30 => CGEventFlags(0x20000000), // 48 

0x31 => CGEventFlags(0x20000000), // 49 
0x31 => CGEventFlags(0x20000000), // 49 
0x31 => CGEventFlags(0x20000000), // 49 

0x32 => CGEventFlags(0x20000000), // 50 
0x32 => CGEventFlags(0x20000000), // 50 
0x32 => CGEventFlags(0x20000000), // 50 

0x33 => CGEventFlags(0x20000000), // 51 
0x33 => CGEventFlags(0x20000000), // 51 
0x33 => CGEventFlags(0x20000000), // 51 

0x34 => CGEventFlags(0x20000000), // 52 
0x34 => CGEventFlags(0x20000000), // 52 
0x34 => CGEventFlags(0x20000000), // 52 

0x35 => CGEventFlags(0x20000000), // 53 
0x35 => CGEventFlags(0x20000000), // 53 
0x35 => CGEventFlags(0x20000000), // 53 

0x36 => CGEventFlags(0x20000000), // 54 
0x36 => CGEventFlags(CGEventFlagCommand | 0x20000010), // 54 
0x36 => CGEventFlags(0x20000000), // 54 

0x37 => CGEventFlags(0x20000000), // 55 
0x37 => CGEventFlags(CGEventFlagCommand | 0x20000008), // 55 
0x37 => CGEventFlags(0x20000000), // 55 

0x38 => CGEventFlags(0x20000000), // 56 
0x38 => CGEventFlags(CGEventFlagShift | 0x20000002), // 56 
0x38 => CGEventFlags(0x20000000), // 56 

0x39 => CGEventFlags(0x20000000), // 57 
0x39 => CGEventFlags(CGEventFlagAlphaShift | 0x20000000), // 57 
0x39 => CGEventFlags(0x20000000), // 57 

0x3a => CGEventFlags(0x20000000), // 58 
0x3a => CGEventFlags(CGEventFlagAlternate | 0x20000020), // 58 
0x3a => CGEventFlags(0x20000000), // 58 

0x3b => CGEventFlags(0x20000000), // 59 
0x3b => CGEventFlags(CGEventFlagControl | 0x20000001), // 59 
0x3b => CGEventFlags(0x20000000), // 59 

0x3c => CGEventFlags(0x20000000), // 60 
0x3c => CGEventFlags(CGEventFlagShift | 0x20000004), // 60 
0x3c => CGEventFlags(0x20000000), // 60 

0x3d => CGEventFlags(0x20000000), // 61 
0x3d => CGEventFlags(CGEventFlagAlternate | 0x20000040), // 61 
0x3d => CGEventFlags(0x20000000), // 61 

0x3e => CGEventFlags(0x20000000), // 62 
0x3e => CGEventFlags(CGEventFlagControl | 0x20002000), // 62 
0x3e => CGEventFlags(0x20000000), // 62 

0x3f => CGEventFlags(0x20000000), // 63 
0x3f => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 63 
0x3f => CGEventFlags(0x20000000), // 63 

0x40 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 64 
0x40 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 64 
0x40 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 64 

0x41 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 65 
0x41 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 65 
0x41 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 65 

0x42 => CGEventFlags(0x20000000), // 66 
0x42 => CGEventFlags(0x20000000), // 66 
0x42 => CGEventFlags(0x20000000), // 66 

0x43 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 67 
0x43 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 67 
0x43 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 67 

0x44 => CGEventFlags(0x20000000), // 68 
0x44 => CGEventFlags(0x20000000), // 68 
0x44 => CGEventFlags(0x20000000), // 68 

0x45 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 69 
0x45 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 69 
0x45 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 69 

0x46 => CGEventFlags(0x20000000), // 70 
0x46 => CGEventFlags(0x20000000), // 70 
0x46 => CGEventFlags(0x20000000), // 70 

0x47 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 71 
0x47 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 71 
0x47 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 71 

0x48 => CGEventFlags(0x20000000), // 72 
0x48 => CGEventFlags(0x20000000), // 72 
0x48 => CGEventFlags(0x20000000), // 72 

0x49 => CGEventFlags(0x20000000), // 73 
0x49 => CGEventFlags(0x20000000), // 73 
0x49 => CGEventFlags(0x20000000), // 73 

0x4a => CGEventFlags(0x20000000), // 74 
0x4a => CGEventFlags(0x20000000), // 74 
0x4a => CGEventFlags(0x20000000), // 74 

0x4b => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 75 
0x4b => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 75 
0x4b => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 75 

0x4c => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 76 
0x4c => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 76 
0x4c => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 76 

0x4d => CGEventFlags(0x20000000), // 77 
0x4d => CGEventFlags(0x20000000), // 77 
0x4d => CGEventFlags(0x20000000), // 77 

0x4e => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 78 
0x4e => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 78 
0x4e => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 78 

0x4f => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 79 
0x4f => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 79 
0x4f => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 79 

0x50 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 80 
0x50 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 80 
0x50 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 80 

0x51 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 81 
0x51 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 81 
0x51 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 81 

0x52 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 82 
0x52 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 82 
0x52 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 82 

0x53 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 83 
0x53 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 83 
0x53 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 83 

0x54 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 84 
0x54 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 84 
0x54 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 84 

0x55 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 85 
0x55 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 85 
0x55 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 85 

0x56 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 86 
0x56 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 86 
0x56 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 86 

0x57 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 87 
0x57 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 87 
0x57 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 87 

0x58 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 88 
0x58 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 88 
0x58 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 88 

0x59 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 89 
0x59 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 89 
0x59 => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 89 

0x5a => CGEventFlags(0x20000000), // 90 
0x5a => CGEventFlags(0x20000000), // 90 
0x5a => CGEventFlags(0x20000000), // 90 

0x5b => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 91 
0x5b => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 91 
0x5b => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 91 

0x5c => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 92 
0x5c => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 92 
0x5c => CGEventFlags(CGEventFlagNumericPad | 0x20000000), // 92 

0x5d => CGEventFlags(0x20000000), // 93 
0x5d => CGEventFlags(0x20000000), // 93 
0x5d => CGEventFlags(0x20000000), // 93 

0x5e => CGEventFlags(0x20000000), // 94 
0x5e => CGEventFlags(0x20000000), // 94 
0x5e => CGEventFlags(0x20000000), // 94 

0x5f => CGEventFlags(0x20000000), // 95 
0x5f => CGEventFlags(0x20000000), // 95 
0x5f => CGEventFlags(0x20000000), // 95 

0x60 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 96 
0x60 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 96 
0x60 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 96 

0x61 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 97 
0x61 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 97 
0x61 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 97 

0x62 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 98 
0x62 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 98 
0x62 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 98 

0x63 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 99 
0x63 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 99 
0x63 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 99 

0x64 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 100 
0x64 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 100 
0x64 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 100 

0x65 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 101 
0x65 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 101 
0x65 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 101 

0x66 => CGEventFlags(0x20000000), // 102 
0x66 => CGEventFlags(0x20000000), // 102 
0x66 => CGEventFlags(0x20000000), // 102 

0x67 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 103 
0x67 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 103 
0x67 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 103 

0x68 => CGEventFlags(0x20000000), // 104 
0x68 => CGEventFlags(0x20000000), // 104 
0x68 => CGEventFlags(0x20000000), // 104 

0x69 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 105 
0x69 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 105 
0x69 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 105 

0x6a => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 106 
0x6a => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 106 
0x6a => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 106 

0x6b => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 107 
0x6b => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 107 
0x6b => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 107 

0x6c => CGEventFlags(0x20000000), // 108 
0x6c => CGEventFlags(0x20000000), // 108 
0x6c => CGEventFlags(0x20000000), // 108 

0x6d => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 109 
0x6d => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 109 
0x6d => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 109 

0x6e => CGEventFlags(0x20000000), // 110 
0x6e => CGEventFlags(0x20000000), // 110 
0x6e => CGEventFlags(0x20000000), // 110 

0x6f => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 111 
0x6f => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 111 
0x6f => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 111 

0x70 => CGEventFlags(0x20000000), // 112 
0x70 => CGEventFlags(0x20000000), // 112 
0x70 => CGEventFlags(0x20000000), // 112 

0x71 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 113 
0x71 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 113 
0x71 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 113 

0x72 => CGEventFlags(CGEventFlagHelp | CGEventFlagSecondaryFn | 0x20000000), // 114 
0x72 => CGEventFlags(CGEventFlagHelp | CGEventFlagSecondaryFn | 0x20000000), // 114 
0x72 => CGEventFlags(CGEventFlagHelp | CGEventFlagSecondaryFn | 0x20000000), // 114 

0x73 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 115 
0x73 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 115 
0x73 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 115 

0x74 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 116 
0x74 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 116 
0x74 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 116 

0x75 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 117 
0x75 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 117 
0x75 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 117 

0x76 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 118 
0x76 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 118 
0x76 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 118 

0x77 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 119 
0x77 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 119 
0x77 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 119 

0x78 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 120 
0x78 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 120 
0x78 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 120 

0x79 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 121 
0x79 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 121 
0x79 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 121 

0x7a => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 122 
0x7a => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 122 
0x7a => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 122 

0x7b => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 123 
0x7b => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 123 
0x7b => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 123 

0x7c => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 124 
0x7c => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 124 
0x7c => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 124 

0x7d => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 125 
0x7d => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 125 
0x7d => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 125 

0x7e => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 126 
0x7e => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 126 
0x7e => CGEventFlags(CGEventFlagSecondaryFn | CGEventFlagNumericPad | 0x20000000), // 126 

0x7f => CGEventFlags(0x20000000), // 127 
0x7f => CGEventFlags(0x20000000), // 127 
0x7f => CGEventFlags(0x20000000), // 127 

0x80 => CGEventFlags(0x20000000), // 128 
0x80 => CGEventFlags(0x20000000), // 128 
0x80 => CGEventFlags(0x20000000), // 128 

0x81 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 129 
0x81 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 129 
0x81 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 129 

0x82 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 130 
0x82 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 130 
0x82 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 130 

0x83 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 131 
0x83 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 131 
0x83 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 131 

0x84 => CGEventFlags(0x20000000), // 132 
0x84 => CGEventFlags(0x20000000), // 132 
0x84 => CGEventFlags(0x20000000), // 132 

0x85 => CGEventFlags(0x20000000), // 133 
0x85 => CGEventFlags(0x20000000), // 133 
0x85 => CGEventFlags(0x20000000), // 133 

0x86 => CGEventFlags(0x20000000), // 134 
0x86 => CGEventFlags(0x20000000), // 134 
0x86 => CGEventFlags(0x20000000), // 134 

0x87 => CGEventFlags(0x20000000), // 135 
0x87 => CGEventFlags(0x20000000), // 135 
0x87 => CGEventFlags(0x20000000), // 135 

0x88 => CGEventFlags(0x20000000), // 136 
0x88 => CGEventFlags(0x20000000), // 136 
0x88 => CGEventFlags(0x20000000), // 136 

0x89 => CGEventFlags(0x20000000), // 137 
0x89 => CGEventFlags(0x20000000), // 137 
0x89 => CGEventFlags(0x20000000), // 137 

0x8a => CGEventFlags(0x20000000), // 138 
0x8a => CGEventFlags(0x20000000), // 138 
0x8a => CGEventFlags(0x20000000), // 138 

0x8b => CGEventFlags(0x20000000), // 139 
0x8b => CGEventFlags(0x20000000), // 139 
0x8b => CGEventFlags(0x20000000), // 139 

0x8c => CGEventFlags(0x20000000), // 140 
0x8c => CGEventFlags(0x20000000), // 140 
0x8c => CGEventFlags(0x20000000), // 140 

0x8d => CGEventFlags(0x20000000), // 141 
0x8d => CGEventFlags(0x20000000), // 141 
0x8d => CGEventFlags(0x20000000), // 141 

0x8e => CGEventFlags(0x20000000), // 142 
0x8e => CGEventFlags(0x20000000), // 142 
0x8e => CGEventFlags(0x20000000), // 142 

0x8f => CGEventFlags(0x20000000), // 143 
0x8f => CGEventFlags(0x20000000), // 143 
0x8f => CGEventFlags(0x20000000), // 143 

0x90 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 144 
0x90 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 144 
0x90 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 144 

0x91 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 145 
0x91 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 145 
0x91 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 145 

0x92 => CGEventFlags(0x20000000), // 146 
0x92 => CGEventFlags(0x20000000), // 146 
0x92 => CGEventFlags(0x20000000), // 146 

0x93 => CGEventFlags(0x20000000), // 147 
0x93 => CGEventFlags(0x20000000), // 147 
0x93 => CGEventFlags(0x20000000), // 147 

0x94 => CGEventFlags(0x20000000), // 148 
0x94 => CGEventFlags(0x20000000), // 148 
0x94 => CGEventFlags(0x20000000), // 148 

0x95 => CGEventFlags(0x20000000), // 149 
0x95 => CGEventFlags(0x20000000), // 149 
0x95 => CGEventFlags(0x20000000), // 149 

0x96 => CGEventFlags(0x20000000), // 150 
0x96 => CGEventFlags(0x20000000), // 150 
0x96 => CGEventFlags(0x20000000), // 150 

0x97 => CGEventFlags(0x20000000), // 151 
0x97 => CGEventFlags(0x20000000), // 151 
0x97 => CGEventFlags(0x20000000), // 151 

0x98 => CGEventFlags(0x20000000), // 152 
0x98 => CGEventFlags(0x20000000), // 152 
0x98 => CGEventFlags(0x20000000), // 152 

0x99 => CGEventFlags(0x20000000), // 153 
0x99 => CGEventFlags(0x20000000), // 153 
0x99 => CGEventFlags(0x20000000), // 153 

0x9a => CGEventFlags(0x20000000), // 154 
0x9a => CGEventFlags(0x20000000), // 154 
0x9a => CGEventFlags(0x20000000), // 154 

0x9b => CGEventFlags(0x20000000), // 155 
0x9b => CGEventFlags(0x20000000), // 155 
0x9b => CGEventFlags(0x20000000), // 155 

0x9c => CGEventFlags(0x20000000), // 156 
0x9c => CGEventFlags(0x20000000), // 156 
0x9c => CGEventFlags(0x20000000), // 156 

0x9d => CGEventFlags(0x20000000), // 157 
0x9d => CGEventFlags(0x20000000), // 157 
0x9d => CGEventFlags(0x20000000), // 157 

0x9e => CGEventFlags(0x20000000), // 158 
0x9e => CGEventFlags(0x20000000), // 158 
0x9e => CGEventFlags(0x20000000), // 158 

0x9f => CGEventFlags(0x20000000), // 159 
0x9f => CGEventFlags(0x20000000), // 159 
0x9f => CGEventFlags(0x20000000), // 159 

0xa0 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 160 
0xa0 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 160 
0xa0 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 160 

0xa1 => CGEventFlags(0x20000000), // 161 
0xa1 => CGEventFlags(0x20000000), // 161 
0xa1 => CGEventFlags(0x20000000), // 161 

0xa2 => CGEventFlags(0x20000000), // 162 
0xa2 => CGEventFlags(0x20000000), // 162 
0xa2 => CGEventFlags(0x20000000), // 162 

0xa3 => CGEventFlags(0x20000000), // 163 
0xa3 => CGEventFlags(0x20000000), // 163 
0xa3 => CGEventFlags(0x20000000), // 163 

0xa4 => CGEventFlags(0x20000000), // 164 
0xa4 => CGEventFlags(0x20000000), // 164 
0xa4 => CGEventFlags(0x20000000), // 164 

0xa5 => CGEventFlags(0x20000000), // 165 
0xa5 => CGEventFlags(0x20000000), // 165 
0xa5 => CGEventFlags(0x20000000), // 165 

0xa6 => CGEventFlags(0x20000000), // 166 
0xa6 => CGEventFlags(0x20000000), // 166 
0xa6 => CGEventFlags(0x20000000), // 166 

0xa7 => CGEventFlags(0x20000000), // 167 
0xa7 => CGEventFlags(0x20000000), // 167 
0xa7 => CGEventFlags(0x20000000), // 167 

0xa8 => CGEventFlags(0x20000000), // 168 
0xa8 => CGEventFlags(0x20000000), // 168 
0xa8 => CGEventFlags(0x20000000), // 168 

0xa9 => CGEventFlags(0x20000000), // 169 
0xa9 => CGEventFlags(0x20000000), // 169 
0xa9 => CGEventFlags(0x20000000), // 169 

0xaa => CGEventFlags(0x20000000), // 170 
0xaa => CGEventFlags(0x20000000), // 170 
0xaa => CGEventFlags(0x20000000), // 170 

0xab => CGEventFlags(0x20000000), // 171 
0xab => CGEventFlags(0x20000000), // 171 
0xab => CGEventFlags(0x20000000), // 171 

0xac => CGEventFlags(0x20000000), // 172 
0xac => CGEventFlags(0x20000000), // 172 
0xac => CGEventFlags(0x20000000), // 172 

0xad => CGEventFlags(0x20000000), // 173 
0xad => CGEventFlags(0x20000000), // 173 
0xad => CGEventFlags(0x20000000), // 173 

0xae => CGEventFlags(0x20000000), // 174 
0xae => CGEventFlags(0x20000000), // 174 
0xae => CGEventFlags(0x20000000), // 174 

0xaf => CGEventFlags(0x20000000), // 175 
0xaf => CGEventFlags(0x20000000), // 175 
0xaf => CGEventFlags(0x20000000), // 175 

0xb0 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 176 
0xb0 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 176 
0xb0 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 176 

0xb1 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 177 
0xb1 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 177 
0xb1 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 177 

0xb2 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 178 
0xb2 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 178 
0xb2 => CGEventFlags(CGEventFlagSecondaryFn | 0x20000000), // 178 

0xb3 => CGEventFlags(0x20000000), // 179 
0xb3 => CGEventFlags(0x20000000), // 179 
0xb3 => CGEventFlags(0x20000000), // 179 

0xb4 => CGEventFlags(0x20000000), // 180 
0xb4 => CGEventFlags(0x20000000), // 180 
0xb4 => CGEventFlags(0x20000000), // 180 

0xb5 => CGEventFlags(0x20000000), // 181 
0xb5 => CGEventFlags(0x20000000), // 181 
0xb5 => CGEventFlags(0x20000000), // 181 

0xb6 => CGEventFlags(0x20000000), // 182 
0xb6 => CGEventFlags(0x20000000), // 182 
0xb6 => CGEventFlags(0x20000000), // 182

I don't know what the flag 0x20000000 means or why it is always set. All keys after 0xb6 don't set a KeyFlag (other than 0x20000000).

Here is the list of keys that set a KeyFlag when they are pressed AND ALSO when they get released:

        Sticky keys:
        0x40 // F17
        0x41
        0x43
        0x45
        0x47
        0x4b
        0x4c
        0x4e
        0x4f // F18
        0x50 // F19
        0x51
        0x52
        0x53
        0x54
        0x55
        0x56
        0x57
        0x58
        0x59
        0x5b
        0x5c
        0x60 // F5
        0x61 // F6
        0x62 // F7
        0x63 // F3
        0x64 // F8
        0x65 // F9
        0x67 // F11
        0x69 // F13
        0x6a // F16
        0x6b // F14
        0x6d // F10
        0x6f // F12
        0x71 // F15
        0x72 // HELP
        0x73 // HOME
        0x74 // PAGE_UP
        0x75 // FORWARD_DELETE
        0x76 // F4
        0x77 // END
        0x78 // F2
        0x79 // PAGE_DOWN
        0x7a // F1
        0x7b // LEFT_ARROW
        0x7c // RIGHT_ARROW
        0x7d // DOWN_ARROW
        0x7e // UP_ARROW
        0x81
        0x82
        0x83
        0x90
        0x91
        0xa0
        0xb0
        0xb1
        0xb2

I confirmed that all keys that get pressed after one of these "sticky keys" will also have the KeyFlags from the sticky key set.

This data might not be 100% reliable because for example the ShiftLock key does not work in the implementation that was used to determine the keyflags. In order for ShiftLock to work, the CGEventFlagAlphaShift must get toggled on a key press. Curiously there is also a NX_DEVICE_ALPHASHIFT_STATELESS_MASK but apparently it does not get set with ShiftLock.

@pentamassiv pentamassiv marked this pull request as draft October 27, 2024 11:42
@pentamassiv pentamassiv force-pushed the macos_no_sleep branch 2 times, most recently from 3ddfd60 to a34ef64 Compare October 27, 2024 11:49
@pentamassiv
Copy link
Collaborator Author

The old implementation had another issue with the EventFlags. When you pressed a modifier and then typed text, the first chunk would not have any flags set but the following chunks would have the flags set. Because of this only the first chunk would get typed. We need to double check the flags. I am especially concerned with the "sticky keys". Ideally we should observe real events and not the one from a previous implementation.

@pentamassiv pentamassiv force-pushed the macos_no_sleep branch 3 times, most recently from a11886a to 0b59684 Compare October 27, 2024 13:27
There were two reasons why we needed to sleep on macOS. The OS needed "some time" to apply a modifier
and correctly set the CGEventFlags. We can remove the sleep and manually set the flags. Another
reason for the sleeps is that all pending events get ignored when the program terminates. The sleeps
were needed so that the OS had enough time to handle all events before the Enigo struct gets dropped.
Sleeps during the execution are much more annoying then at the end of the program, so there is now a
sleep for two seconds when the Enigo struct gets dropped. I just assumed that to be enough for most cases.
I did not find a way to ask the OS if all events were handled. We could probably do better here and
calculate a duration based on the time when the last event was sent and how many were sent.

Other things that were fixed:
- Thanks to the sleep in the Drop trait of Enigo, moving the mouse also works if it is the only function
  that gets executed. It used to finish too fast and we didn't have a sleep so it got ignored because
  Enigo was dropped before it was handled by the OS
- By manually setting the EventFlags, CapsLock now also works. Before this commit, sending text would fail
  if a modifier was held and the text was too small to be sent as one chunk.
@pentamassiv pentamassiv marked this pull request as ready for review October 27, 2024 13:38
@pentamassiv pentamassiv merged commit f3403c8 into enigo-rs:main Oct 27, 2024
24 checks passed
@pentamassiv pentamassiv deleted the macos_no_sleep branch October 27, 2024 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant