问题
I am writing a bash script to automatically detect when my USB keyboard is plugged into my laptop (running Ubuntu 14), so I can change the keyboard layout automatically.
Here is my code so far (I got it from another post on Stack Overflow so I'm not 100% sure how it works)
#!/bin/bash
setxkbmap es
for dev in /sys/bus/usb/devices/ *-*:*
do
if [ -f $dev/bInterfaceClass ]
then
if [[ "$(cat $dev/bInterfaceClass)" == "03" && "$(cat $dev/bInterfaceProtocol)" == "01" ]]
then
setxkbmap gb
fi
fi
done
I have got this to run on startup so far... But I'd like it to run every time a USB device is connected or disconnected.
It is important that I have it all run in one Bash script and not as a .rules file in ...udev/... or anything. However, a single Python script will do just as well.
回答1:
Thanks to ralf htp I was able to come up with the following solution. It has the following improvements:
- It is not dependent on specific keyboards, it will treat all USB keyboards in the same way.
- If the user manually switches to a different keyboard layout (one which is neither the default or the USB keyboard's) it will not automatically switch it back to the default or USB layout.
Please feel free to improve this code at GitHub Gist
#!/bin/bash
kbd1=es #default keyboard layout
kbd2=gb #USB keyboard layout
flag=0
while true
do
layout="$(setxkbmap -query | grep -a layout | cut -c13-14)"
if [[ $layout == $kbd1 ]] || [[ $layout == $kbd2 ]]
then
for dev in /sys/bus/usb/devices*-*
do
if [ -f $dev/bInterfaceClass ]
then
if [[ "$(cat $dev/bInterfaceClass)" == "03" && "$(cat
$dev/bInterfaceProtocol)" == "01" ]]
then
if [[ "$flag" == "0" ]]
then
setxkbmap $kbd2
fi
flag=1
break
fi
if [[ "$flag" == "1" ]]
then
setxkbmap $kbd1
fi
flag=0
fi
done
fi
sleep 5s
done
回答2:
this works because on linux system the file system structure is always the same
cat $dev/bInterfaceClass
queries every usb device for its interface class
cat $dev/bInterfaceProtocol
queries every usb device for its interface protocol
try ls /sys/bus/usb/devices/
and you see all usb device nodes
then select one i.e. ls /sys/bus/usb/devices/usb1
and use ls /sys/bus/usb/devices/usb1/idVendor
instead of bInterfaceProtocol
i would use idVendor
and idProduct
you can determine product ID and vendor ID of your keyboard by attaching the keyboard and using lsusb
and picking it from the listing
UPDATE
following script will do it. insert the vendor and product id of your device. maybe test before without the setxkbmap
command. the flag
variable is used for not settingthe keyboard map every 5 seconds ...
#!/bin/bash
flag=0
while true
do
for dev in /sys/bus/usb/devices/*-*
do
if [ -f $dev/idVendor ]
then
if [[ "$(cat $dev/idVendor)" == "your_vendor_id" && "$(cat $dev/idProduct)" == "your_product_id" ]]
then
if [[ "$flag" == "0" ]]
then
echo 'USB device attached'
setxkbmap gb
fi
flag=1
break
fi
if [[ "$flag" == "1" ]]
then
echo 'USB device detached'
setxkbmap es
fi
flag=0
fi
done
sleep 5s
done
note that for setxkbmap
to be working you have to install x11-xkb-utils
( https://superuser.com/questions/404457/how-to-change-keyboard-layout-while-in-console )
来源:https://stackoverflow.com/questions/43265185/bash-how-to-run-code-whenever-usb-device-is-connected