As far as I can tell, this is done via DDC/CI. But I don’t think DDC supports any kind of display-initiated events. Which means some software on the PC constantly has to poll the screen to tell that something changed. Which of course cannot be done too quickly or it would start to waste resources.
Benq has a video online, that shows their Auto Pivot feature with Windows, and the quite notable delay seems to suggest this is the case for their Windows drivers.
Of course, on Linux, this is quite trivial to replicate.
All you need is a script that runs in the background, with a loop that polls the DDC value indicating the rotation, and sleeps a bit until the next poll. If it found that the value changed, it would run xrandr to rotate the display. Throw this into your init system of choice, and you’re done. It’s not pretty, because polling never is. (Interrupts would be the correct way to do something like this.) But it works.
As a plus, you can set the polling time, and I made it so that if you need to trigger anything else from this, you can just drop it in the correct directory.
#! /bin/bash
# Some older systems might prefer using “/usr/bin/env bash” above.
# Internals
declare -A values
configDir="$( [[ "$UID" == 0 ]] && echo "/etc/ddc-event/" || echo "$HOME/.config/dde-event" )"
debugMode=true
# (First time, each time) initialization
if [[ ! -e "$configDir/config" ]]; then
$debugMode && echo "Creating configuration in ”$configDir/config”."
mkdir -p "$configDir"
cat > "$configDir/config" <<-EOD
delay=1 # seconds
features=( AA ) # Set your VCPs here, separated be a space character. Find them via “ddcutil capabilities”.
debugMode=true
EOD
fi
. "$configDir/config" # Loads configuration
for feature in ${features[@]}; do
$debugMode && echo "Creating handler directories for features ( ${features[*]} ) in ”$configDir/”."
[[ -e "$configDir/$feature" ]] || mkdir -p "$configDir/$feature"
done
# Handler manager
callHandlers() { local feature="$1"; local value="$2";
for handler in "$configDir/$feature/"*; do
$debugMode && echo " Calling handler “$handler” for feature "$feature" with value “$value”."
"$handler" "$value"
done
}
# Main script
while true; do
for feature in ${features[@]}; do
newValue="$( ddcutil -t getvcp "$feature" | cut -d ' ' -f 4 )"
if [[ "$newValue" != "${value[$feature]}" ]]; then
$debugMode && echo "Feature “$feature”: Value “${value[$feature]}” -> “$newValue”."
value[$feature]="$newValue"
callHandlers "$feature" "$newValue"
fi
done
sleep "$delay"
done
Save this in e.g. /usr/local/bin/ddc-event, then chmod +x /usr/local/bin/ddc-event. Install ddcutil, so it works. Now run ddc-event via your init system of choice or just via any session autostart of your desktop or .bashrc (in the background with ddc-event &) or whatever.
Next, place the following rotation handler in either $HOME/.config/ddc-event/AA/pivot or /etc/ddc-event/AA/pivot, depending on whether the above daemon runs as your user or as root, and chmod +x it too:
#! /bin/bash
display="DVI-0"
if [[ "$1" == "x01" ]]; then
xrandr --output "$display" --rotation normal
elif [[ "$1" == "x02" ]]; then
xrandr --output "$display" --rotation left
fi
If the directory does not exist, you forgot to run the first script first. :)
After that, you can set which features to look for in $HOME/.config/ddc-event/config or /etc/ddc-event/config, again depending on if it runs as root.
I found a delay of 5 seconds (resulting in 2.5s delay on average) to be perfectly fine. Even 10s might be ok, so it will take very little resources.
The features to look for can be found via ddcutil capabilities (The hex values.). ddc-event should automatically create the directories for the features on launch. You can then throw any scripts in there that you like.
You can also set debugMode=true and just run it from the console, to watch the events come in and handlers get executed.
Finally, if you want to stop it, just kill the process. Nothing special about it, unless your handlers are special.
It’s an universal DDC event handler in the classic Unix/Linux style.
I hope this finally solved the problem. :)