Bash - How to run code whenever USB device is connected

China☆狼群 提交于 2021-02-10 15:43:40

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!