Уголок новичка
   2108

udevrules и Xbox gamepad

Прокунсультируйте кто-нибудь по udevrules.
предпосылки: при игре с помощью геймпада, монитор вырубается — уходит в спящий режим. нагуглил решение — маленькая утилита из aur — joystickwake. только ее нужно запускать в фоне перед запуском игры, а потом вырубать (можно не вырубать, но борьба за ресурсы, все дела).
задача — выполнять скрипт при подключении геймпада, а при отключении выполнять еще один.
пытаюсь освоить udevrules, а тут еще и подвернулся повод)
что делаю:
dmesg
[ 3558.815661] usb 1-4: new full-speed USB device number 20 using xhci_hcd
[ 3558.960747] usb 1-4: New USB device found, idVendor=045e, idProduct=02ea, bcdDevice= 3.01
[ 3558.960753] usb 1-4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 3558.960757] usb 1-4: Product: Controller
[ 3558.960760] usb 1-4: Manufacturer: Microsoft
[ 3558.960763] usb 1-4: SerialNumber: 3033363030303431393237383334
[ 3558.962538] input: Microsoft X-Box One S pad as /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/input/input37

методом «от противного» узнаю, что мой гемпад коннектится как /dev/input/js1
sudo udevadm info -a -n /dev/input/js1
looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/input/input28/js1':
KERNEL==«js1»
SUBSYSTEM==«input»
DRIVER==""
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0/input/input28':
KERNELS==«input28»
SUBSYSTEMS==«input»
DRIVERS==""
ATTRS{name}==«Microsoft X-Box One S pad»
ATTRS{uniq}==""
ATTRS{properties}==«0»
ATTRS{phys}==«usb-0000:00:14.0-4/input0»
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4:1.0':
KERNELS==«1-4:1.0»
SUBSYSTEMS==«usb»
DRIVERS==«xpad»
ATTRS{authorized}==«1»
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceNumber}==«00»
ATTRS{bNumEndpoints}==«02»
ATTRS{bInterfaceProtocol}==«d0»
ATTRS{bInterfaceSubClass}==«47»
ATTRS{bInterfaceClass}==«ff»
ATTRS{supports_autosuspend}==«0»
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-4':
KERNELS==«1-4»
SUBSYSTEMS==«usb»
DRIVERS==«usb»
ATTRS{maxchild}==«0»
ATTRS{serial}==«3033363030303431393237383334»
ATTRS{urbnum}==«16»
ATTRS{bcdDevice}==«0301»
ATTRS{bNumConfigurations}==«1»
ATTRS{bMaxPower}==«500mA»
ATTRS{bNumInterfaces}==" 3"
ATTRS{bDeviceProtocol}==«d0»
ATTRS{avoid_reset_quirk}==«0»
ATTRS{bmAttributes}==«a0»
ATTRS{version}==" 2.00"
ATTRS{product}==«Controller»
ATTRS{quirks}==«0x0»
ATTRS{bConfigurationValue}==«1»
ATTRS{removable}==«removable»
ATTRS{devpath}==«4»
ATTRS{rx_lanes}==«1»
ATTRS{ltm_capable}==«no»
ATTRS{devnum}==«11»
ATTRS{bMaxPacketSize0}==«64»
ATTRS{idProduct}==«02ea»
ATTRS{manufacturer}==«Microsoft»
ATTRS{bDeviceSubClass}==«47»
ATTRS{configuration}==""
ATTRS{tx_lanes}==«1»
ATTRS{devspec}=="(null)"
ATTRS{bDeviceClass}==«ff»
ATTRS{busnum}==«1»
ATTRS{speed}==«12»
ATTRS{authorized}==«1»
ATTRS{idVendor}==«045e»
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1':
KERNELS==«usb1»
SUBSYSTEMS==«usb»
DRIVERS==«usb»
ATTRS{configuration}==""
ATTRS{idVendor}==«1d6b»
ATTRS{bMaxPacketSize0}==«64»
ATTRS{speed}==«480»
ATTRS{bNumInterfaces}==" 1"
ATTRS{maxchild}==«16»
ATTRS{version}==" 2.00"
ATTRS{bmAttributes}==«e0»
ATTRS{authorized}==«1»
ATTRS{bConfigurationValue}==«1»
ATTRS{devnum}==«1»
ATTRS{authorized_default}==«1»
ATTRS{devspec}=="(null)"
ATTRS{bNumConfigurations}==«1»
ATTRS{bDeviceSubClass}==«00»
ATTRS{bMaxPower}==«0mA»
ATTRS{bDeviceProtocol}==«01»
ATTRS{rx_lanes}==«1»
ATTRS{idProduct}==«0002»
ATTRS{interface_authorized_default}==«1»
ATTRS{vendor}==«0x8086»
ATTRS{local_cpulist}==«0-7»
ATTRS{device}==«0xa12f»
ATTRS{d3cold_allowed}==«1»
ATTRS{broken_parity_status}==«0»
looking at parent device '/devices/pci0000:00':
KERNELS==«pci0000:00»
SUBSYSTEMS==""
DRIVERS==""

создаю:
/etc/udev/rules/50-xbox.rules
SUBSYSTEM==«input», ATTRS{idVendor}==«045e», ATTRS{idProduct}==«02ea», ACTION==«add», RUN+="/etc/udev/scripts/joy.sh"

перезапускаю правила:
sudo udevadm control --reload-rules

проверяю — не работает.
скрипт из консоли запускается. если что, вот его пример:
/etc/udev/scripts/joy.sh
#!/bin/bash
joystickwake && notify-send «Xbox gamepad connected» -t 1000

короче, победа.

решил отказаться от всяких joystickwake и использовать топорный метод xset. конечный вариант правила:
/etc/udev/rules.d/98-xbox.rules
ACTION=="add" \
, KERNEL=="js1" \
, ATTRS{name}=="Microsoft X-Box One S pad" \
, RUN+="/bin/bash /etc/udev/scripts/joyadd.sh"

ACTION=="remove" \
, KERNEL=="js1" \
, ATTRS{name}=="Microsoft X-Box One S pad" \
, RUN+="/bin/bash /etc/udev/scripts/joyrem.sh"

# Wireless gamepad
ACTION=="add" \
, KERNEL=="input[0-9]*" \
, ATTRS{name}=="Xbox Wireless Controller" \
, RUN+="/bin/bash /etc/udev/scripts/joyadd.sh (BT)"

ACTION=="remove" \
, ATTRS{name}=="Xbox Wireless Controller" \
, RUN+="/bin/bash /etc/udev/scripts/joyrem.sh (BT)"

конечный вариант скриптов:
/etc/udev/scripts/joyadd.sh
#!/bin/bash
TIME='-t 1000'
STAT=$1
DISPLAY=":0"
XAUTHORITY=/run/user/1000/Xauthority
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
export DISPLAY XAUTHORITY DBUS_SESSION_BUS_ADDRESS
xset -dpms
xset s off
su led -c "notify-send  'System Message' 'Xbox Gamepad $STAT connected' $TIME"

/etc/udev/scripts/joyrem.sh
#!/bin/env bash
TIME='-t 1000'
STAT=$1
DISPLAY=":0"
XAUTHORITY=/run/user/1000/Xauthority
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
export DISPLAY XAUTHORITY DBUS_SESSION_BUS_ADDRESS
xset +dpms
xset s on
su led -c "notify-send  'Sytem Message' 'Xbox Gamepad $STAT disconnected' $TIME"



но, при отключении bluetooth ивент срабатывает дважды. не особо критично, но…

11 комментариев

avatar
  1. Не проще вместо idVendor и idProduct использовать name?
  2. Вы вызываете тулзу, которая будет приостанавливать блокировщик экрана. Не лучше ли напрямую приостанавливать блокировку?
  3. У Вас в правиле ни слова о том, что скрипт должен запускатья от пользователя.
 
Альтернативные решения.
  • Смотреть в сторону WM и менеджера питания — умеет ли что-то из них отслеживать полноэкранные окна.
  • Также проблему можно решить с изяществом тарана в рамках принципа KISS средствами xautolock либо xset. Просто и надежно.
  • LightsOn, LightsOnPlus и disable_dpms. Отключают DPMS при обнаружении приложений из списка и полноэкранных окон. Для отключения скринлокера может потребоваться минимальный допил.
  • Caffeine(-ng).
  • Слать геймпадом фейковые клавиатурные нажатия. Но в данном случае это костыль.
К плюсам этих вариантов стоит отнести то, что подключенный геймпад не останавливает скринсейвер полностью, что выглядит весьма логичным.
Последний раз редактировалось
0
avatar
альтернативными я накостылял скрипт, который при запуске игры каждые 5 минут проверяет работает ли игра или нет. и добавил его к ярлыку игры, но зотелось бы разобраться с devrules
само правило с name
ACTION=="add", ATTRS{name}=="Microsoft X-Box One S pad", RUN+="/bin/bash /etc/udev/scripts/joy.sh"

скрипт:
notify-send "bla-bla-bla"

не работает(
0
avatar
скрипт, который при запуске игры каждые 5 минут проверяет работает ли игра или нет
Caffeine работает именно так. Но, ИМХО, наиболее красивым решением является обнаружение полноэкранных окон.
не работает(
Удав работает от рута. И скрипт запускает от рута. Но su пока никто не отменял.
RUN+="/bin/su $USERNAME_HERE -c /etc/udev/scripts/joy.sh"

Получается коряво если юзверей больше одного, но работать с указанным должно. Вопрос с пользователями, в принципе, решаем путем парсинга вывода w(ho).
Для вывода уведомления может понадобиться указать значение DISPLAY.
Последний раз редактировалось
0
avatar
сделал вот так:
ACTION=="add" \
, ATTRS{name}=="Microsoft X-Box One S pad" \
, RUN+="/bin/su $(/usr/bin/who | /bin/awk \{print\ \$1\}) -c /etc/udev/scripts/joy.sh"


и добавил в sudoers для joy.sh запуск без запроса пароля пользователя. из терминала запускается, из правила udev не хочет.
пробовал в скрипт вставить
#!/bin/env bash
export XAUTHORITY=/run/user/$UID/Xauthority
export DISPLAY=:0
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$UID/bus"

/usr/bin/notify-send 'WARNING'

не работает, хотя само правило отрабатывает. проверил с помощью отключения тачпада при подключении геймпада)
RUN+="/bin/xinput --disable 16"


походу проблема только с кастомными скриптами, но как ее решить — ума не приложу(

ну и отслеживать окна. открытые на весь экран особо нечем. i3wm из архитекта с минимальным набором пакетов.

UPD: походу какая-то трабла с notify-send… без него все работает. ну и ладно.
Последний раз редактировалось
0
avatar
и добавил в sudoers для joy.sh запуск без запроса пароля пользователя
Лишнее, по идее, при запуске с правами рута.
из терминала запускается, из правила udev не хочет
Если прямо указать имя пользователя — то же самое?
отслеживать окна. открытые на весь экран особо нечем
xprop -id $WINDOW _NET_WM_STATE | grep --quiet _NET_WM_STATE_FULLSCREEN

Но xprop в минимальную поставку вроде как не входит.
export XAUTHORITY=/run/user/$UID/Xauthority
  1. Попробуйте сделать
    su $USERNAME_HERE -c echo $UID
    Выхлоп пуст.
  2. .Xauthority же. И лежит хомяке.
Последний раз редактировалось
+1
avatar
то же самое)
ну xprop в принципе тоже можно использовать. спс за идею)
но мои костыли без notify-send проработали до перезагрузки и сломались)
теперь при подключении геймпада udev запускает аж 3 скрипта с joystickwake и потом исчезает из процессов)))
магия)
у меня Xauthority на хомяке не лежит. я его перенес)

su led -c echo $UID


в выхлопе пусто… странно…
Последний раз редактировалось
0
avatar
Рабочая конструкция для отправки сообщений в графическую сессию пользователя. Но $UID все равно нужен.
su $USERNAME_HERE -c "DISPLAY=$DISPLAY_HERE DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$UID_HERE/bus notify-send -i 'TITLE_HERE' 'MESSAGE_HERE'

Есть функция для поиска UID, DISPLAY и USER
function notify-send() {
    #Detect the name of the display in use
    local display=":$(ls /tmp/.X11-unix/* | sed 's#/tmp/.X11-unix/X##' | head --lines=1)"

    #Detect the user using such display
    local user=$(who | grep '('$display')' | cut --fields=1 --delimiter=' ' | head --lines=1)

    #Detect the id of the user
    local uid=$(id --user $user)

    sudo -u $user DISPLAY=$display DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus notify-send "$@"
}

С этим от можно перенести все пляски с пользователем в сам скрипт, а удав пусть себе пускает как ему нравится.
Последний раз редактировалось
0
avatar
вот так заработало, но скрипт подключения запускается трижды, а отключения дважды)магия
0
avatar
Странно. А если сдвинуть правило с 99 сильно повыше?
0
avatar
попробовал и вверх и вниз. тот же результат. добавил в правило, KERNEL==«js1»
теперь notify-send отрабатывает один раз, но не запускается joystickwake. вернее, он пытается запуститься, его попытки даже видно в htop, но потом сразу падает(
0
avatar
спасибо большое за помощь. закостылил как хотелось. конечные варианты в теме положил. пригодится)
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.