Skip to content

Instantly share code, notes, and snippets.

@wheresjames
Created August 21, 2024 19:30
Show Gist options
  • Save wheresjames/2f9b2c3d261d6a531f71e2786b59a89a to your computer and use it in GitHub Desktop.
Save wheresjames/2f9b2c3d261d6a531f71e2786b59a89a to your computer and use it in GitHub Desktop.
Map touch screens to displays
#!/bin/bash
#--------------------------------------------------
# Set touchscreen to monitor mapping
declare -A mapping
mapping["ELAN9008:00 04F3:4063"]="eDP-1"
mapping["ELAN9009:00 04F3:4068"]="DP-1"
#--------------------------------------------------
# Generic
fix_width() {
local input="$1"
local width="$2"
input=$(echo "$input" | sed 's/\.0*$//' | sed 's/\(\.[0-9]*[1-9]\)0*$/\1/')
if [ ${#input} -gt $width ]; then
input="${input:0:$width}"
else
while ((${#input} < $width)); do
input="$input "
done
fi
echo "$input"
}
#--------------------------------------------------
# Show pointer devices
# Connected pointing devices
echo "--- Pointer devices ---"
xinput list | grep "slave pointer"
echo
#--------------------------------------------------
# Get monitor information
# Get monitor information
monitor_info=$(xrandr --query | grep ' connected')
# Extract monitor names, resolutions, and positions
declare -A monitors
longest_name=0
while IFS= read -r line; do
name=$(echo $line | awk '{print $1}')
resolution=$(echo $line | grep -oP '[0-9]+x[0-9]+\+[0-9]+\+[0-9]+')
width=$(echo $resolution | cut -d'x' -f1)
height=$(echo $resolution | cut -d'x' -f2 | cut -d'+' -f1)
x_pos=$(echo $resolution | cut -d'+' -f2)
y_pos=$(echo $resolution | cut -d'+' -f3)
if [ ${#name} -gt $longest_name ]; then
longest_name=${#name}
fi
monitors[$name]="$width $height $x_pos $y_pos"
done <<< "$monitor_info"
# Example output of monitor information
echo "--- Monitor information ---"
for name in "${!monitors[@]}"; do
echo "Monitor: $(fix_width "$name" $longest_name) -- ${monitors[$name]}"
done
echo
#--------------------------------------------------
# Calculate total screen dimensions
min_x=0
min_y=0
max_x=0
max_y=0
for info in "${monitors[@]}"; do
width=$(echo $info | cut -d' ' -f1)
height=$(echo $info | cut -d' ' -f2)
x_pos=$(echo $info | cut -d' ' -f3)
y_pos=$(echo $info | cut -d' ' -f4)
# Calculate extents for x
if [ $x_pos -lt $min_x ]; then
min_x=$x_pos
fi
right_edge=$((x_pos + width))
if [ $right_edge -gt $max_x ]; then
max_x=$right_edge
fi
# Calculate extents for y
if [ $y_pos -lt $min_y ]; then
min_y=$y_pos
fi
bottom_edge=$((y_pos + height))
if [ $bottom_edge -gt $max_y ]; then
max_y=$bottom_edge
fi
done
# Calculate total width and height considering negative offsets
total_width=$((max_x - min_x))
total_height=$((max_y - min_y))
# Total dimensions
echo "Total Width : $total_width"
echo "Total Height: $total_height"
#--------------------------------------------------
# Map touchscreen to monitor
map_touchscreen_to_monitor() {
touchscreen_name=$1
monitor_name=$2
if [ -z "${monitors[$monitor_name]}" ]; then
echo "Monitor $monitor_name not found."
exit 1
fi
# Get monitor's width, height, x_pos, and y_pos
width=$(echo ${monitors[$monitor_name]} | cut -d' ' -f1)
height=$(echo ${monitors[$monitor_name]} | cut -d' ' -f2)
x_pos=$(echo ${monitors[$monitor_name]} | cut -d' ' -f3)
y_pos=$(echo ${monitors[$monitor_name]} | cut -d' ' -f4)
# Adjust x_pos and y_pos to be relative to the overall screen space
adjusted_x_pos=$((x_pos - min_x))
adjusted_y_pos=$((y_pos - min_y))
# Calculate the transformation matrix
x_scale=$(bc -l <<< "$width / $total_width")
y_scale=$(bc -l <<< "$height / $total_height")
x_trans=$(bc -l <<< "$adjusted_x_pos / $total_width")
y_trans=$(bc -l <<< "$adjusted_y_pos / $total_height")
# sw = touch_area_width / total_width
# sh = touch_area_height / total_height
# xo = touch_area_x_offset / total_width
# yo = touch_area_y_offset / total_height
#
# The matrix is
# [ sw 0 xo ]
# [ 0 sh yo ]
# [ 0 0 1 ]
# Apply the transformation matrix using xinput
xinput --map-to-output "$touchscreen_name" "$monitor_name"
xinput set-prop "$touchscreen_name" "Coordinate Transformation Matrix" $x_scale 0 $x_trans 0 $y_scale $y_trans 0 0 1
echo
echo "Mapped $touchscreen_name to $monitor_name"
echo "[ $(fix_width $x_scale 6) 0 $(fix_width $x_trans 6) ]"
echo "[ 0 $(fix_width $y_scale 6) $(fix_width $y_trans 6) ]"
echo "[ 0 0 1 ]"
echo "X = ${x_trans:0:6} --> ${x_scale:0:6}"
echo "Y = ${y_trans:0:6} --> ${y_scale:0:6}"
}
for touchscreen in "${!mapping[@]}"; do
monitor=${mapping[$touchscreen]}
map_touchscreen_to_monitor "$touchscreen" "$monitor"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment