Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mierzejk/c71d9c110a74844a41906337d22caff6 to your computer and use it in GitHub Desktop.
Save mierzejk/c71d9c110a74844a41906337d22caff6 to your computer and use it in GitHub Desktop.
Two bash scripts to get xinput id of a pointing device that is listed more than once by the same name, and apply it for setting the device properties.
#!/usr/bin/env bash
args=$@
function str_strip() {
xargs echo -n <<< $1
}
function has_arg() {
[[ $args =~ (^|[[:blank:]])$1([[:blank:]]|$) ]]
}
DEVICE_NAME=$(str_strip "$DEVICE_NAME")
[[ ${DEVICE_NAME:=$(str_strip "$1")} ]] || exit 1
DEVICE_NUM=$(str_strip "$DEVICE_NUM")
[[ ${DEVICE_NUM:=$(str_strip "$2")} ]] || DEVICE_NUM=0
function xinput_pointer_ids() {
pref="^[^[:alnum:]]*↳"
xinput list --short | sed -n -E -e "0,/${pref/↳/}Virtual[[:blank:]]core[[:blank:]]pointer.*master[[:blank:]]pointer/Id" \
-e "/$pref/"'!q1' \
-e "s/$pref[[:blank:]]*//; p" \
| perl -ne "s|^$1\s+id=(\d+)\s+.*?pointer.*$|\$1|i && print"
}
function name_by_id() {
xinput --list-props $1 | awk 'BEGIN{FS=":[ \t]*"}/^[ \t]*Device Node \(/ {print substr($2, 2, length($2)-2)}'
}
function is_usb_intfnum_by_id() {
if [[ ${#2} -lt 2 ]]; then
num="00${2}"
num=${num: -2}
else num=$2; fi
[[ $(udevadm info --query=property --name=$(name_by_id $1) 2>/dev/null | awk 'BEGIN{FS="="}/^[ \t]*ID_USB_INTERFACE_NUM/ {print $2}') = $num ]]
}
ids=($(xinput_pointer_ids "$DEVICE_NAME"))
[[ ${#ids[@]} -eq 1 ]] && ! has_arg "-f" && ! has_arg "--force" && echo -n $ids && exit 0
for id in ${ids[@]}; do
if $(is_usb_intfnum_by_id $id "$DEVICE_NUM"); then echo -n $id && exit 0; fi
done
exit 1

The scripts returns (echos) xinput id of a pointing device by its name, and if the name is not unique also by its USB interface number.
It is suggested to set the script mode to grant execute permissions.

Arguments

Name Position Mandatory Default value Description
DEVICE_NAME 1 yes The device name as reported by xinput list.
DEVICE_NUM 2 optional 0 The device USB interface number: udev's bInterfaceNumber / ID_USB_INTERFACE_NUM value.
If the value is one character (digit) only, then it is left padded with 0.
flags:
-f or --force
last optional absent If the flag is present, always compare DEVICE_NUM value, even if there is only one device with DEVICE_NAME.

Both DEVICE_NAME and DEVICE_NUM values can be passed either as positional arguments, or in front in the form of environment variables.

Exit codes

  • 0 on success: xinput id is returned.
  • 1 otherwise: DEVICE_NAME is empty or not listed by xinput list, or DEVICE_NUM does not match any udev's bInterfaceNumber / ID_USB_INTERFACE_NUM value.

Examples

mouse_id=$(DEVICE_NAME="Razer Razer DeathAdder V2 X HyperSpeed" ./get_pointer_id.sh)
./get_pointer_id.sh "Razer Razer DeathAdder V2 X HyperSpeed" 1 -f; echo -e "\nExit code: $?"

Side notes

  • The script should also work for keyboard devices if you replace every pointer character string with keyboard in all bash / grep / perl / awk / sed regular expressions, but I have not tested it yet.
  • DEVICE_NAME (and DEVICE_NUM) values are stripped, and all whitespace sequences are replace with a single space character (U+0020: ' '). If this behaviour is unwanted, simply delete all str_strip function invocations.

Finding DEVICE_NUM value

If you are not sure what the right DEVICE_NUM value is for your pointing device, follow the instructions:

  1. Execute xinput list --short and note down all you device's id values ({device_id} hereinafter).
  2. For every {device_id}, find its Device Node value with xinput --list-props {device_id}. The outcome should be like Device Node (278): "/dev/input/event20".
    You can also ease it with the following snippet extracted from the name_by_id function:
xinput --list-props {device_id} | awk 'BEGIN{FS=":[ \t]*"}/^[ \t]*Device Node \(/ {print substr($2, 2, length($2)-2)}'
  1. Use the cat command to open the sysfs Device Node file. For example:
cat /dev/input/event20
  1. Move the mouse, and then terminate cat with Ctrl+C. If you could observe some characters being printed out to the terminal, it is very likely you have found correct Device Node. Otherwise, please repeat steps 2., 3., and 4. for the next {device_id} value.
  2. Find Device Node's ID_USB_INTERFACE_NUM value with udevadm info --query=property --name={Device Node}. The outcome should be like ID_USB_INTERFACE_NUM=00, and these digits are precisely your DEVICE_NUM value. If it is 00, then you are good to go with the script's default DEVICE_NUM argument value.
    You can also use the following snippet extracted from the is_usb_intfnum_by_id function:
udevadm info --query=property --name={Device Node} | awk 'BEGIN{FS="="}/^[ \t]*ID_USB_INTERFACE_NUM/ {print $2}'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment