regla udev para cargar automáticamente la distribución del teclado cuando el teclado usb está enchufado

24

Estoy tratando de cargar un nuevo diseño de teclado cuando conecto un teclado usb pero mi regla udev no funciona.

SUBSISTEMA == "input", ATTR {idVendor} == "062a", ATTR {idProduct} == "0201", GOTO = "usb_xmodmap_auto"

LABEL = "usb_xmodmap_auto"
ACCIÓN == "agregar", EJECUTAR + = "/ usr / bin / xmodmap ~ / .usbXmodmap"
ACCIÓN == "eliminar", EJECUTAR + = "/ usr / bin / xmodmap ~ / .pndXmodmap"

He recargado las reglas usando:

> sudo udevadm control --reload-rules

y reiniciando el sistema, pero cuando conecto el teclado usb, el xmodmap original todavía está cargado y, por lo tanto, la distribución del teclado es incorrecta, pero si ejecuto el comando en el terminal

> / usr / bin / xmodmap ~ / .usbXmodmap
o
> / usr / bin / xmodmap ~ / .pndXmodmap

Funcionan bien.

Espero que alguien pueda ayudar.

Editar:

solo para ayudar más, ejecuté algunas pruebas de udevadm:

> prueba de udevadm --acción = agregar /dispositivos/plataforma/ehci-omap.0/usb1/1-2/1-2.3/1-2.3:1.1/input/input10

salidas:

run_command: llamando: prueba
udevadm_test: versión 151
Este programa es solo para depuración, no ejecuta ningún programa,
especificado por una tecla RUN. Puede mostrar resultados incorrectos, porque
algunos valores pueden ser diferentes o no estar disponibles en una ejecución de simulación.

[...]
archivo_parse: lectura '/etc/udev/rules.d/usb-keyboard.rules' como archivo de reglas
udev_rules_new: las reglas usan tokens de 100572 bytes (8381 * 12 bytes), búfer de 21523 bytes
udev_rules_new: índice temporal utilizado 35380 bytes (1769 * 20 bytes)
udev_device_new_from_syspath: el dispositivo 0x3b4d8 tiene devpath '/devices/platform/ehci-omap.0/usb1/1-2/1-2.3/1-2.3:1.1/input/input10'
udev_rules_apply_to_event: RUN '/ sbin / modprobe -b $ env {MODALIAS}' /etc/udev/rules.d/80-drivers.rules:5
udev_rules_apply_to_event: RUN 'socket: @ / org / freedesktop / hal / udev_event' /etc/udev/rules.d/90-hal.rules:2
udev_rules_apply_to_event: RUN '/ sbin / modprobe $ env {MODALIAS}' /etc/udev/rules.d/local.rules:31
udev_rules_apply_to_event: EJECUTAR 'socket: / org / kernel / udev / monitor' /etc/udev/rules.d/run.rules:2
udev_rules_apply_to_event: RUN '/ usr / bin / xmodmap ~ / .usbXmodmap' /etc/udev/rules.d/usb-keyboard.rules:4
udevadm_test: UDEV_LOG = 6
udevadm_test: DEVPATH = / devices / platform / ehci-omap.0 / usb1 / 1-2 / 1-2.3 / 1-2.3: 1.1 / input / input10
udevadm_test: PRODUCT = 3 / 62a / 201/110
udevadm_test: NAME = "Teclado compatible con USB"
udevadm_test: PHYS = "usb-ehci-omap.0-2.3 / input1"
udevadm_test: UNIQ = ""
udevadm_test: EV == 1f
udevadm_test: KEY == 837fff 2c3027 bf004444 0 0 1fe3 c04 a27c000 267bfa d941dfed 9e0000 0 0 0
udevadm_test: REL == 143
udevadm_test: ABS == 1 0
udevadm_test: MSC == 10
udevadm_test: MODALIAS = input: b0003v062Ap0201e0110-e0,1,2,3,4, k71,72,73,74,77,80,82,83,85,86,87,88,89,8A, 8B, 8C, 8E, 8F, 90,96,98,9B, 9C, 9E, 9F, A1, A3, A4, A5, A6, A7, A8, A9, AB, AC, AD, AE, B1, B2, B5, CE, CF, D0, D1, D2, D5, D9, DB, E2, EA, EB, 100,101,105,106,107,108,109,10A, 10B, 10C, 162,166,16A, 16E, 178,179,17A, 17B, 17C, 17D, 17F, 180,181,182,185,18C, 18D, 192,193,195,1A0,1A1,1A2,1A3,1A4,1A5,1A6,1A7,1A8,1A9,1AA, 1AB, 1AC, 1AD, 1AE, 1B0,1B1,1B7, r0,1,6,8, a20, m4, lsfw
udevadm_test: ACTION = agregar
udevadm_test: SUBSYSTEM = input
udevadm_test: run: '/ sbin / modprobe -b input: b0003v062Ap0201e0110-e0,1,2,3,4, k71,72,73,74,77,80,82,83,85,86,87,88,89 , 8A, 8B, 8C, 8E, 8F, 90,96,98,9B, 9C, 9E, 9F, A1, A3, A4, A5, A6, A7, A8, A9, AB, AC, AD, AE, B1 , B2, B5, CE, CF, D0, D1, D2, D5, D9, DB, E2, EA, EB, 100,101,105,106,107,108,109,10A, 10B, 10C, 162,166,16A, 16E, 178,179,17A, 17B, 17C, 17D , 17F, 180,181,182,185,18C, 18D, 192,193,195,1A0,1A1,1A2,1A3,1A4,1A5,1A6,1A7,1A8,1A9,1AA, 1AB, 1AC, 1AD, 1AE, 1B0,1B1,1B7, r0,1 , 6,8, a20, m4, lsfw '
udevadm_test: run: 'socket: @ / org / freedesktop / hal / udev_event'
udevadm_test: run: '/ sbin / modprobe input: b0003v062Ap0201e0110-e0,1,2,3,4, k71,72,73,74,77,80,82,83,85,86,87,88,89,8A , 8B, 8C, 8E, 8F, 90,96,98,9B, 9C, 9E, 9F, A1, A3, A4, A5, A6, A7, A8, A9, AB, AC, AD, AE, B1, B2 , B5, CE, CF, D0, D1, D2, D5, D9, DB, E2, EA, EB, 100,101,105,106,107,108,109,10A, 10B, 10C, 162,166,16A, 16E, 178,179,17A, 17B, 17C, 17D, 17F , 180,181,182,185,18C, 18D, 192,193,195,1A0,1A1,1A2,1A3,1A4,1A5,1A6,1A7,1A8,1A9,1AA, 1AB, 1AC, 1AD, 1AE, 1B0,1B1,1B7, r0,1,6 , 8, a20, m4, lsfw '
udevadm_test: ejecutar: 'socket: / org / kernel / udev / monitor'
udevadm_test: run: '/ usr / bin / xmodmap ~ / .usbXmodmap'

y

> prueba de udevadm - acción = eliminar /devices/platform/ehci-omap.0/usb1/1-2/1-2.3/1-2.3:1.1/input/input10

salidas:

run_command: llamando: prueba
udevadm_test: versión 151
Este programa es solo para depuración, no ejecuta ningún programa,
especificado por una tecla RUN. Puede mostrar resultados incorrectos, porque
algunos valores pueden ser diferentes o no estar disponibles en una ejecución de simulación.

[...]
archivo_parse: lectura '/etc/udev/rules.d/usb-keyboard.rules' como archivo de reglas
udev_rules_new: las reglas usan tokens de 100572 bytes (8381 * 12 bytes), búfer de 21523 bytes
udev_rules_new: índice temporal utilizado 35380 bytes (1769 * 20 bytes)
udev_device_new_from_syspath: el dispositivo 0x3b4d8 tiene devpath '/devices/platform/ehci-omap.0/usb1/1-2/1-2.3/1-2.3:1.1/input/input10'
udev_rules_apply_to_event: RUN 'socket: @ / org / freedesktop / hal / udev_event' /etc/udev/rules.d/90-hal.rules:2
udev_rules_apply_to_event: EJECUTAR 'socket: / org / kernel / udev / monitor' /etc/udev/rules.d/run.rules:2
udev_rules_apply_to_event: RUN '/ usr / bin / xmodmap ~ / .pndXmodmap' /etc/udev/rules.d/usb-keyboard.rules:5
udevadm_test: UDEV_LOG = 6
udevadm_test: DEVPATH = / devices / platform / ehci-omap.0 / usb1 / 1-2 / 1-2.3 / 1-2.3: 1.1 / input / input10
udevadm_test: PRODUCT = 3 / 62a / 201/110
udevadm_test: NAME = "Teclado compatible con USB"
udevadm_test: PHYS = "usb-ehci-omap.0-2.3 / input1"
udevadm_test: UNIQ = ""
udevadm_test: EV == 1f
udevadm_test: KEY == 837fff 2c3027 bf004444 0 0 1fe3 c04 a27c000 267bfa d941dfed 9e0000 0 0 0
udevadm_test: REL == 143
udevadm_test: ABS == 1 0
udevadm_test: MSC == 10
udevadm_test: MODALIAS = input: b0003v062Ap0201e0110-e0,1,2,3,4, k71,72,73,74,77,80,82,83,85,86,87,88,89,8A, 8B, 8C, 8E, 8F, 90,96,98,9B, 9C, 9E, 9F, A1, A3, A4, A5, A6, A7, A8, A9, AB, AC, AD, AE, B1, B2, B5, CE, CF, D0, D1, D2, D5, D9, DB, E2, EA, EB, 100,101,105,106,107,108,109,10A, 10B, 10C, 162,166,16A, 16E, 178,179,17A, 17B, 17C, 17D, 17F, 180,181,182,185,18C, 18D, 192,193,195,1A0,1A1,1A2,1A3,1A4,1A5,1A6,1A7,1A8,1A9,1AA, 1AB, 1AC, 1AD, 1AE, 1B0,1B1,1B7, r0,1,6,8, a20, m4, lsfw
udevadm_test: ACTION = eliminar
udevadm_test: SUBSYSTEM = input
udevadm_test: run: 'socket: @ / org / freedesktop / hal / udev_event'
udevadm_test: ejecutar: 'socket: / org / kernel / udev / monitor'
udevadm_test: run: '/ usr / bin / xmodmap ~ / .pndXmodmap'

lo que parece mostrar que debería funcionar, pero no espera que esto ayude a obtener una respuesta.

Jake Aitchison
fuente

Respuestas:

16

Encontré una manera de evitar esto, aunque es un poco hacky.

Hoy llegué al mismo punto exacto al tratar de configurar dos teclados con udev, setxkbmap y xinput --list y para que trabajen con la conexión en caliente del usb. Estoy intercambiando teclas, sin cambiar el diseño, pero es todo lo mismo, una vez que haya identificado su teclado en un hotplug y pueda llamar a setxkbmap, entonces debería poder configurar el idioma solo del teclado que ha especificado . La lista de diseños de teclado se puede encontrar aquí ls -l /usr/share/kbd/keymaps/i386/y puede encontrar el nombre de su dispositivo para trabajar con gre xinput -list.

  1. Querrá reemplazarlo rizumucon su nombre de usuario, ya que descubrí que no era posible hacer esto sin ser explícito.
  2. Asegúrate de apretar el yournombre del teclado.
  3. Utilícelo lsusbpara descubrir la ID de hardware que necesita establecer en la regla udev. Mi teclado das se ve asíBus 002 Device 009: ID 04d9:2013 Holtek Semiconductor, Inc.

Primero configuré la regla de udev para autodetectar el teclado creando una regla de udev:

En el archivo /etc/udev/rules.d/00-usb-keyboards.rules:

ACTION=="add", ATTRS{idVendor}=="04d9", ATTRS{idProduct}=="2013", RUN+="/home/rizumu/bin/kbd_udev", OWNER="rizumu"

Tengo dos archivos ~ / bin / kbd y ~ / bin / kbd_udev. Asegúrese de que tengan los permisos correctoschmod 755 ~/bin/kbd*

El ~/bin/kbd_udevscript contiene:

#!/bin/bash
/home/rizumu/bin/kbd &

Y notará que todo lo que hace es llamar ~/bin/kbden segundo plano, para que udev pueda completar su proceso y activar el teclado. Dentro del ~/bin/kbdscript dormimos por un segundo, porque necesitamos esperar hasta que el teclado se active para que podamos obtener la identificación del dispositivo usando xinput. Para este achive He puesto algunas variables y los exportaban por lo setxkbmap xinput puede hacer emabrgo trabajo: DISPLAY, XAUTHORITY, HOME, y uno daskb_idpara el ID de mi daskeyboard:

#!/bin/bash
sleep 1
DISPLAY=":0.0"
HOME=/home/rizumu/
XAUTHORITY=$HOME/.Xauthority
export DISPLAY XAUTHORITY HOME
daskb_id=`xinput -list | grep -i 'daskeyboard' | grep -o id=[0-9]. | grep -o [0-9]. | head -1`

xset r rate 200 30
setxkbmap -layout colemak
setxkbmap -option ctrl:nocaps
if [ "${daskb_id}" ]; then
    setxkbmap -device "${daskb_id}" -option altwin:swap_lalt_lwin
fi
Thomas Schreiber
fuente
Muchas gracias por ayudarme a responder mi propia pregunta es AskUbuntu: askubuntu.com/questions/337411/…
Sadi
Y me pregunto si también puede ayudarme a agregar un mensaje de notificación al final de este script (por ejemplo notify-send "USB Keyboard is plugged in and ready for use now." -i gtk-dialog-info -t 1000 -u normal). Como no sé mucho acerca de las secuencias de comandos, intenté insertarlo antes o después de "fi", pero en ambos casos el mensaje de notificación seguía apareciendo una y otra vez :-(
Sadi
¿Por qué configurar OWNEReste dispositivo?
Limbo Peng
1
¿Qué hace la xset r rate 200 30línea? xsetno está disponible en mi instalación de Ubuntu 17.04.
kleinfreund
1
No puedo ejecutar xmodmap $HOME/.Xmodmapusando un script análogo a su "/ home / rizumu / bin / kbd". ¿Por qué sería eso?
Geremia
5

Dependiendo de su distribución, es posible que ya tenga una regla udev para teclados en /lib/udev/rules.d/64-xorg-xkb.rules. En Ubuntu, esto importa / etc / default / keyboard, que tiene opciones más o menos así:

XKBMODEL="pc105"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS=""

Para mi configuración, descubrí que esta regla incorporada se estaba ejecutando después de mi regla udev personalizada y estaba anulando mi configuración. En cambio, cambié XKBOPTIONS en / etc / default / keyboard para que sea:

XKBOPTIONS="-option ctrl:nocaps"

Para obtener el comportamiento "Bloqueo de mayúsculas es control" que quería en todos los teclados.

jsha
fuente
2
¡Gran idea! El mío funciona con soloXBKOPTIONS="ctrl:nocaps"
RasmusWL
3

Si está ejecutando GNOME, deberá deshabilitar su complemento de administración del teclado para que no anule los cambios de diseño.

gconftool-2 --toggle /apps/gnome_settings_daemon/plugins/keyboard/active

Ejecute el mismo comando nuevamente para habilitarlo como desee.

Ignacio Vazquez-Abrams
fuente
Estoy corriendo angstrom. ¿esto funcionara?
Jake Aitchison
¿Estás usando GNOME en Ångström?
Ignacio Vázquez-Abrams
no estoy usando xfce 4.6.1
Jake Aitchison
1
En mi Ubuntu 13.04, esto está dconfdebajo /org/gnome/settings-daemon/plugins/keyboard/active.
nh2
1
Y el comando para Ubuntu 13.04 es:gsettings set org.gnome.settings-daemon.plugins.keyboard active false
Sadi
3

No funciona porque udev y xmodmapno tienen acceso a la pantalla X11. De hecho, udevni siquiera sabe si no son pantallas X11 activos.

  • Nota: pantallas , plural. No puede usar "la" pantalla X11 porque puede haber más de una. Por ejemplo, si usa "cambio rápido de usuario".
Gravedad
fuente
Entonces, ¿cómo podría hacer que esto funcione?
Jake Aitchison
Alguien sabe cómo puedo solucionar esto?
Jake Aitchison
1
He conseguido que udev llame a setxkbmap. La regla de udev llama a un script que pone en segundo plano otro script (para que udev pueda completar). El segundo script hace una pausa por un segundo, configura las variables X11 esperadas y activa setxkbmap. Vea mi respuesta a la pregunta principal para más detalles.
Thomas Schreiber
@rizumu: Ahh, buena suerte para que eso funcione con GDM.
Grawity
3

Creo que encontré una forma mucho más limpia de configurar esto, que no requiere un hack X11 especial.

La idea detrás de esto es que udevsolo detectará nuevas entradas de teclado y creará un enlace simbólico para cada diseño, luego inotifybuscará un nuevo diseño en el espacio de usuario.

reglas de udev

#/etc/udev/rules.d/61-usb-keyboard-layout.rules

# will match my Logitech keyboard with US layout 
SUBSYSTEM=="input", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c31c", GROUP="plugdev", MODE="0660", SYMLINK+="input/by-layout/us"

# will match my Lenovo integrated keyboard with IT layout
SUBSYSTEM=="input", ENV{ID_PATH}=="platform-i8042-serio-0", SYMLINK+="input/by-layout/it"

# force the directory to be recreated, just in case you unplug all input
SUBSYSTEM=="input", RUN="/bin/mkdir -p /dev/input/by-layout"

Con estas reglas, tengo un directorio en dev ( /dev/input/by-layout) para ver los cambios en los scripts de espacio de usuario.

Script de espacio de usuario para KDE

Por ejemplo, cuando uso KDE tengo este script (automático) ejecutándose:

#!/bin/bash

# In case no link are found, switch to this layout
DEFAULT="it"

switch_layout () {
        [ ! -z "$1" ] || return 0
        /usr/bin/qdbus org.kde.keyboard /Layouts org.kde.KeyboardLayouts.setLayout $1
}

best_layout() {
        local LAYOUT=$(ls -1t /dev/input/by-layout/ | head -n 1)
        if [ -z "$LAYOUT" ] ; then
                LAYOUT=$DEFAULT
        fi
        echo $LAYOUT
}

switch_layout $(best_layout)

while true ; do
        EVENT=$(inotifywait -q -e create -e delete --exclude '.*tmp.*' /dev/input/by-layout/)

        if echo "$EVENT" | grep -qe CREATE ; then
                LAYOUT=${EVENT#?*CREATE }
        fi

        if echo "$EVENT" | grep -qe DELETE ; then
                LAYOUT=$(best_layout)
        fi

        switch_layout $LAYOUT
done

Esto funciona como un encanto para mí. Para cambiar el diseño del sistema (que no necesito en este momento), loadkeysse puede demonizar un script similar que se usa con un script de inicio del sistema.

giosh94mhz
fuente
Gracias, esto me hizo darme cuenta de que solo puedo usar inotifywaitpara ejecutar un script de configuración en cualquier cambio /dev/input, ya que el script en sí es idempotente.
Charlie Gorichanaz
3

¿Qué pasa con la configuración X.Org? De Gentoo Wiki: X.Org/Input_drivers - udev :

Ejemplo: si tiene un teclado Logitech Access para la parte francesa de Suiza, puede usar lo siguiente:

Archivo: /etc/X11/xorg.conf.d/10-keyboard.conf

Section "InputClass"
    Identifier             "evdev keyboard catchall"
    MatchIsKeyboard        "on"
    MatchDevicePath        "/dev/input/event*"
    Driver                 "evdev"
    Option                 "XkbModel" "logiaccess"
    Option                 "XkbLayout" "ch"
    Option                 "XkbVariant" "fr"
EndSection

Para una explicación en profundidad, lea:

man xorg.conf

y:

man evdev

ArchWiki demuestra el uso de la misma sintaxis en xorg.conf pero señala que "hoy en día debe crear un archivo de configuración separado, como /etc/X11/xorg.conf.d/90-keyboard-layouts.conf". Uso Arch y configuré mi propio teclado USB en el /etc/X11/xorg.conf.d/vim 10-evdev.conf existente. Funcionó para mí.

@rizumu: Kludge inteligente, gracias por compartir.

Casey Jones
fuente
1
No tengo un directorio x.org.conf.d en Linux Mint 18.2
Max N
2

Para responder a su pregunta sobre cómo acceder a la pantalla en ejecución, puede exportar la variable DISPLAY apropiada en el script, suponiendo que los permisos para la pantalla estén configurados correctamente. ( man xsetpara permisos de visualización).

En muchos casos habituales puedes simplemente export DISPLAY=:0 para el comando, ya que esa es la primera pantalla en un solo sistema de usuario. Probablemente sea más fácil ejecutar un script en lugar de xmodmap directamente, ya que esto le permitirá tener más control sobre las variables de entorno y el resto. (Por lo tanto, reemplace "/ usr / bin / xmodmap ~ / .usbXmodmap" en su regla con "/usr/local/bin/keyboard_plug.sh" y coloque los comandos apropiados en ese script junto con la variable DISPLAY).

Sin embargo, como se señaló anteriormente, si asume DISPLAY =: 0, puede tener problemas más adelante si tiene múltiples usuarios o pantallas. Puede escribir scripts para detectar la pantalla adecuada, pero en ese caso está solo (en lo que respecta a esta respuesta). :)

rust_and_moth
fuente
1

Como no pude obtener los trucos para que las reglas de udev funcionen, escribí un pequeño script de Python pyudevpara monitorear los eventos de entrada.

#! /usr/bin/env python3

import pyudev
import time
import subprocess

ctx = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(ctx)
monitor.filter_by("input")

def defer_xmodmap():
    time.sleep(1) # not sure if there's a race here, but it feels like there could be.
    subprocess.run("xmodmap ~/dotfiles/.xmodmap", shell=True)


for device in iter(monitor.poll, None):
    # there might be a way to add the action condition to the filter, but I couldn't find it
    if device.action != "add":
        continue

    # ensure the KB is initialized -- not sure if this is actually a needed check
    if not device.is_initialized:
        continue

    # my keyboard, from the output of `lsusb`
    if not "045E:07A5" in device.device_path:
        continue

    # it's the keyboard being added.
    defer_xmodmap()

Luego uso este archivo de unidad de usuario systemd para mantenerlo en funcionamiento ( systemctl --user enable name_of_service_file):

[Unit]
Description=udev xmodmap monitor

[Service]
ExecStart=/usr/bin/env python3 %h/local/bin/monitor_kb_udev
Restart=always
RestartSec=10

[Install]
WantedBy=default.target

La inotifywaitsolución de @ giosh94mhz es un poco más simple y evita la dependencia de pyudev. Sin embargo, por alguna razón, descubrí que el inotifyevento no se activaba durante 10-20 segundos después de conectar mi teclado.

Ryan Marcus
fuente