Skip to content

Add feature to run shell scripts or send URL notifications on various events #4320

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

Open
waydabber opened this issue Apr 28, 2025 · 10 comments
Open
Labels
enhancement New feature or request integration Command-line interface

Comments

@waydabber
Copy link
Owner

The app now sends distributed notifications on various control events - it would be nice if the app could also run scripts or call URLs.

@waydabber waydabber added enhancement New feature or request integration Command-line interface labels Apr 28, 2025
@waydabber
Copy link
Owner Author

waydabber commented Apr 28, 2025

By https://github.com/manishprivet (originally posted here: MonitorControl/MonitorControl#1752 (reply in thread))


Thanks for the quick reply, and for the project as well. It is a life changer!!!

I checked the BetterDisplay shortly after commenting, and I was so glad I found it. However it reaches only 80% of my use-case, so I would like to make this feature request for BetterDisplay instead.

I am currently using the CLI like this to display volume in Sketchybar (ref)

elif command -v betterdisplaycli 2>&1 >/dev/null; then
  if [ "$VOLUME" = "missing value" ]; then
    ALTERNATE_VOLUME=$(betterdisplaycli get -feature=volume -value -displayWithMainStatus | bc)

    MEGA=100

    if [[ $ALTERNATE_VOLUME =~ "." ]]; then
      VOLUME=$(bc -l <<<"${ALTERNATE_VOLUME}*${MEGA}" | bc)
      VOLUME=$(echo "$VOLUME" | cut -d. -f1)
    fi

    MUTE=$(betterdisplaycli get -feature=mute -value -displayWithMainStatus)

    if [ "$MUTE" = "on" ]; then
      VOLUME="0"
    fi
  fi
fi

However, I currently have to run the script as a cron job since I am not sure how to catch events from BetterDisplay and run a shell command after I change volume.

For example, in aerospace, I have this to trigger an event inside sketchybar (ref)

exec-on-workspace-change = ['/bin/bash', '-c',
    'sketchybar --trigger aerospace_workspace_change'
]

And I was hoping BetterDisplay/MonitorControl also had something like this. In the documentation I can find a way to catch the event in a Swift application. If there is a simpler alternative to that, I would appreciate that a lot.

@waydabber
Copy link
Owner Author

Oh, I see - so you need sketchybar to do something when you change the volume in BetterDisplay? Well, you can do it in a somewhat roundabout way - you can create an integration control for volume, use shell script as integration method, add your command to trigger sketchybar and also add a CLI command to directly adjust the DDC volume (by addressing the right VCP). By setting up integration controls for volume and mute, the app's volume slider, keyboard etc will use that instead of DDC volume (which you can as well turn that off under DDC Features).

@manishprivet
Copy link

Thanks @waydabber for considering the request.

Regarding

you can create an integration control for volume, use shell script as integration method, add your command to trigger sketchybar and also add a CLI command to directly adjust the DDC volume

I guess this suggestion can work, I will try it tomorrow and let you know. But it still feels very hacky and brittle. I was hoping for a way to control these things via dotfiles, but maybe that is a too big of an ask 😅

If you can add a hook in app to trigger a shell script on volume change, that will simplify things a little bit though as you said.
Thanks again

@waydabber
Copy link
Owner Author

I don't think I'll implement dotfiles based configuration - things are a bit difficult to keep track now just as they are. The app solely uses macOS user defaults for configuration so one can reach (query and modify, export import) any settings that via terminal using defaults (true, it is fully undocumented, but the app's plist file is easily readable and the right settings can be figured out) - this is a rather open and scripting friendly solution I think. Starting to add various configuration and event descriptors via dotfiles would at best be a selective/partial solution (the capability would cover only specific settings) and would probably be rather confusing, I don't think many would use it.

(but maybe I misunderstand the request :))

@manishprivet
Copy link

manishprivet commented Apr 28, 2025

I added the integration control like this

Image

And I turned of the Volume in DDC Control Settings like this

Image

However the command in Integration Control doesn't seem to be executing when I am changing volume with Media keys.

For Example

betterdisplaycli set -ddc -vcp=audioSpeakerVolume -value=30

This works fine in my terminal.

However I hardcoded the value here in the Shell Script section, but changing the volume through media keys is still not updating the volume level of my monitor.

@waydabber
Copy link
Owner Author

Try to add a log output there (by attaching something like 2>> ~/Desktop/log.txt or something similar) so you see what the issue is. Maybe betterdisplaycli is not in the path. You can try using the absolute path or even a path to the app binary itself. But in addition to the betterdisplaycli call you'll also need to add your stuff there. You can also generally try some other command like mkdir ~/Desktop/[*:VALUE:*] and see if a folder is created on your desktop with a value - so you can check if your scripts do run. You can start the app with -v to see what command is sent exactly or check the Console with the right filters - https://github.com/waydabber/BetterDisplay/wiki/Enable-console-logging.

@manishprivet
Copy link

Thanks @waydabber for the help. Using absolute path fixed this.

Image

However I cannot find the correct vcp for the mute feature, can you help with that? As without a get value script in Integration controls for volume mute betterdisplaycli get -feature=mute -value is failing.

Also even if this is functional, changing volume rapidly doesn't register all instances of the command unfortunately like the native integration does 😞

If having a callback feature is possible, that will make things a lot smoother.

@waydabber
Copy link
Owner Author

The display might not support mute and getting mute state rarely works. The app by default actually sets both volume to 0 on mute and sends the mute command as well.

The problem might be rate limiting/debouncing - I will add this as feature for integration controls (until that time you can do so in a script). Also, sometimes a single DDC send with volume might be ineffective, so you can simply try sending the DDC request twice.

@waydabber
Copy link
Owner Author

(Note: An other entirely different approach is to simply reuse the swift example about notifications and create a simple swift executable (daemon) that runs in the background and calls the appropriate script. I think ChatGPT can put one together super quick if you feed the example code.)

@manishprivet
Copy link

simply reuse the swift example about notifications and create a simple swift executable (daemon)

I will try this sometime this weekend.

Thank you for getting the functionality working for me as now I can update the volume in my status-bar real time 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request integration Command-line interface
Projects
None yet
Development

No branches or pull requests

2 participants