enigo-rs / enigo

Cross platform input simulation in Rust
MIT License
893 stars 95 forks source link

Volume up / down doesn't work on MacOS #248

Closed thewh1teagle closed 4 months ago

thewh1teagle commented 6 months ago

Describe the bug Key::VolumeUp doesn't work on macos

Main.rs#L16

Expected behavior Volume goes up or down

Environment (please complete the following information):

Additional context On windows it work

pentamassiv commented 6 months ago

Can you please try with https://crates.io/crates/enigo/0.2.0-rc2?

pentamassiv commented 6 months ago

There were a number of breaking changes. Let me know if you need my help to adapt your code to the new version

pentamassiv commented 6 months ago

@paulora2405 Let's continue the discussion here.

https://github.com/pentamassiv/enigo/issues/28 should give you some pointers. The code relevant to macOS is contained in src/macos_impl.rs. In order to fix the issue, it should be possible to replace lines 352-359 with something like this:

        match key {
            Key::VolumeDown | Key::VolumeDown| ... => {
                debug!("special case for handling the key");
                self.special_keys(key)?;
            }
            _ => {
                let Ok(keycode) = CGKeyCode::try_from(key) else {
                    return Err(InputError::InvalidInput(
                        "virtual keycodes on macOS have to fit into u16",
                    ));
                };
                self.raw(keycode, direction)?;
            }
        }

According to the linked stackOverflow answer, you should be able to write something like this:

    fn special_keys(key: Key) -> InputResult<()> {
        /*
        // Simulate illumination up
        let code = NX_KEYTYPE_ILLUMINATION_UP
        let event1 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xa00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xa << 8 as Int32))), data2: -1)
        event1?.cgEvent?.post(tap: .cghidEventTap)
        let event2 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xb00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xb << 8 as Int32))), data2: -1)
        event2?.cgEvent?.post(tap: .cghidEventTap)

        // Simulate illumination down
        let code = NX_KEYTYPE_ILLUMINATION_DOWN
        let event1 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xa00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xa << 8 as Int32))), data2: -1)
        event1?.cgEvent?.post(tap: .cghidEventTap)
        let event2 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xb00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xb << 8 as Int32))), data2: -1)
        event2?.cgEvent?.post(tap: .cghidEventTap)

                         */
    }

The commented out stuff is Swift code and not correct, but should give a good hint. I believe you have to use a function from the objc crate to get the NSEvent and call the otherEvent fn. Here is some more documentation: https://developer.apple.com/documentation/appkit/nsevent/1530010-otherevent

thewh1teagle commented 6 months ago

@pentamassiv Thanks about letting know of docker-osx. I will check it there and let you know

thewh1teagle commented 6 months ago

I'll try to run it on MacOS somehow; I tried using Mac docker OSX and it's very slow and took me very long to setup that, and then I figured out it doesn't save it's state.

Then I found that I can rent MacOS hourly on Scaleway.com, and it works but still it works with VNC and it's slow.

Anyway, this is how it should work:

  1. We need to emulate media key like that https://stackoverflow.com/questions/11045814/emulate-media-key-press-on-mac
  2. Similar code in rust is https://github.com/Sinono3/souvlaki, it has media controls.

The only thing is that we need to implement that with core-graphics which this library based on

thewh1teagle commented 6 months ago

Further investigation: It's possible to control it using applescript, tried it and it work. create main.applescript file with:

set Outputvol to output volume of (get volume settings)
set volume output volume (Outputvol + 6.25)

the + for vol up, if we change to - it will be vol down

Run with:

osascript main.applescript