I am trying to code a BASH script that will do the following while a program's window has focus. This would be done under KDE:
While holding left mouse button:
- press alt-4 key
- check for color (white) at pixel position 1; if pixel color exists, press alt-1 key
- check for color (white) at pixel position 2; if pixel color exists, press alt-2 key
- check for color (white) at pixel position 3; if pixel color exists, press alt-3 key
Single press mouse button 4:
- toggle script sequence on/off
- press alt-5
I have the following code but it seems to be quite slow. Any way to optimize?
#!/bin/bash
# mouse id. use xinput --list. verify with xinput --query-state [id]
mouse=12
# set colors with xwd. run the following in terminal to get cursor position:
# while true; do xdotool getmouselocation; sleep 0.2; clear; done
while :; do
state="$(xinput --query-state "$mouse")"
color1="$(xwd -root -silent | convert xwd:- -depth 8 -crop "1x1 195 247" txt:- | grep -om1 '#\w\ ')"
color2="$(xwd -root -silent | convert xwd:- -depth 8 -crop "1x1 1407 681" txt:- | grep -om1 '#\w\ ')"
color3="$(xwd -root -silent | convert xwd:- -depth 8 -crop "1x1 1200 256" txt:- | grep -om1 '#\w\ ')"
color4="$(xwd -root -silent | convert xwd:- -depth 8 -crop "1x1 1095 257" txt:- | grep -om1 '#\w\ ')"
color5="$(xwd -root -silent | convert xwd:- -depth 8 -crop "1x1 1195 258" txt:- | grep -om1 '#\w\ ')"
# if lmb (mouse 1) pressed
if [[ "$state" == *"button[1]=down"* ]]; then
if [[ "$color1" == "#FFFFFF" ]]; then
xdotool key --clearmodifiers a
elif [[ "$color2" == *"#FFFFFF"* ]]; then
xdotool key --clearmodifiers b
elif [[ "$color3" == *"#FFFFFF"* ]]; then
xdotool key --clearmodifiers c
elif [[ "$color4" == *"#FFFFFF"* ]]; then
xdotool key --clearmodifiers d
elif [[ "$color5" == *"#FFFFFF"* ]]; then
xdotool key --clearmodifiers e
fi
fi
done
Any help would be appreciated
CodePudding user response:
A couple of things spring to mind...
Firstly, it seems you are not really interested in the colours of the pixels if the left mouse button is not pressed, so I would avoid getting all the colours if that is not the case. I mean:
while :; do
state="$(xinput --query-state "$mouse")"
# Don't do all the xwd | convert | grep stuff here
# if lmb (mouse 1) pressed
if [[ "$state" == *"button[1]=down"* ]]; then
# Do xwd | convert | grep stuff here
fi
done
That should allow you to test more frequently.
Secondly, you are calling xwd
which starts a process and grabs megabytes of data, then starting convert
which is another process that receives megabytes of data and then starting grep
. And you are doing all that 5 times to get just five pixels. So, instead of that, start a single xwd
, a single convert
and get your 5 pixels in one go.
Rather than use xwd
, I am just generating a repeatable, fixed image each time here. Your code does this:
# Make same random image 5 times and extract a single pixel each time
magick -seed 42 -size 100x100 xc: noise random -depth 8 -crop 1x1 10 10 txt:
magick -seed 42 -size 100x100 xc: noise random -depth 8 -crop 1x1 20 20 txt:
magick -seed 42 -size 100x100 xc: noise random -depth 8 -crop 1x1 30 30 txt:
magick -seed 42 -size 100x100 xc: noise random -depth 8 -crop 1x1 40 40 txt:
magick -seed 42 -size 100x100 xc: noise random -depth 8 -crop 1x1 50 50 txt:
which produces this:
# ImageMagick pixel enumeration: 1,1,0,255,srgb
0,0: (120,134,192) #7886C0 srgb(120,134,192)
# ImageMagick pixel enumeration: 1,1,0,255,srgb
0,0: (86,188,188) #56BCBC srgb(86,188,188)
# ImageMagick pixel enumeration: 1,1,0,255,srgb
0,0: (108,12,24) #6C0C18 srgb(108,12,24)
# ImageMagick pixel enumeration: 1,1,0,255,srgb
0,0: (174,137,144) #AE8990 srgb(174,137,144)
# ImageMagick pixel enumeration: 1,1,0,255,srgb
0,0: (44,185,31) #2CB91F srgb(44,185,31)
I am suggesting this:
# Make same random image, but extract 5 pixels in one fell swoop
magick -seed 42 -size 100x100 xc: noise random -depth 8 \
\( -clone 0 -crop 1x1 10 10 \) \
\( -clone 0 -crop 1x1 20 20 \) \
\( -clone 0 -crop 1x1 30 30 \) \
\( -clone 0 -crop 1x1 40 40 \) \
\( -clone 0 -crop 1x1 50 50 \) \
-delete 0 -append txt:
which produces the same 5 pixels in a single 5-pixel image in just one process rather than 5 xwd
processes and 5 convert
processes:
# ImageMagick pixel enumeration: 1,5,0,255,srgb
0,0: (120,134,192) #7886C0 srgb(120,134,192)
0,1: (86,188,188) #56BCBC srgb(86,188,188)
0,2: (108,12,24) #6C0C18 srgb(108,12,24)
0,3: (174,137,144) #AE8990 srgb(174,137,144)
0,4: (44,185,31) #2CB91F srgb(44,185,31)
You might consider piping the output from the previous line into awk
along these lines:
magick -seed 42 -size 100x100 xc: noise random -depth 8 \
\( -clone 0 -crop 1x1 10 10 \) \
...
\( -clone 0 -crop 1x1 50 50 \) \
-delete 0 -append txt: |
awk 'NR==1 {next} /#FFFFFF/ {print "white"; next} {print "not"}'
Then you'll get something along these lines:
not
white
white
not
not
Here is my best effort, bearing in mind I don't have X11 available to me, or even a computer for testing:
while : ; do
# Check if mouse pressed
state="$(xinput --query-state "$mouse")"
if [[ "$state" == *"button[1]=down"* ]]; then
read color1 color2 color3 color4 color5 < <( xwd -root -silent |
convert xwd:- -depth 8 \
\( -clone 0 -crop 1x1 195 247 \) \
\( -clone 0 -crop 1x1 1407 681 \) \
\( -clone 0 -crop 1x1 1200 256 \) \
\( -clone 0 -crop 1x1 1095 257 \) \
\( -clone 0 -crop 1x1 1195 258 \) \
-delete 0 -append txt: |
awk '
NR==1 { out =""; next }
/#FFFFFF/ { out = out "white "; next } { out = out "not " }
END { print out }
' )
echo $color1 $color2 $color3 $color4 $color5
fi
done
If it has some bugs, you can debug it by running like this:
bash -xv THISSCRIPT.sh
or paste it into shellcheck.