reguła udev do automatycznego ładowania układu klawiatury po podłączeniu klawiatury USB

22

Próbuję załadować nowy układ klawiatury po podłączeniu klawiatury USB, ale moja reguła udev nie działa.

SUBSYSTEM == „input”, ATTR {idVendor} == „062a”, ATTR {idProduct} == „0201”, GOTO = „usb_xmodmap_auto”

LABEL = "usb_xmodmap_auto"
ACTION == "add", RUN + = "/ usr / bin / xmodmap ~ / .usbXmodmap"
AKCJA == "usuń", RUN + = "/ usr / bin / xmodmap ~ / .pndXmodmap"

Ponownie załadowałem zasady, używając:

> sudo udevadm control --reload-rules

i poprzez ponowne uruchomienie systemu, ale po podłączeniu klawiatury USB oryginalna xmodmap jest nadal ładowana, a zatem układ klawiatury jest nieprawidłowy, ale jeśli uruchomię polecenie w terminalu

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

działają dobrze.

Mam nadzieję, że ktoś może pomóc.

Edytować:

tylko po to, żeby bardziej pomóc, przeprowadziłem kilka testów udevadm:

> test udevadm --action = add /devices/platform/ehci-omap.0/usb1/1-2/1-2.3/1-2.3:1.1/input/input10

wyjścia:

polecenie_ruchomienia: wywołanie: test
udevadm_test: wersja 151
Ten program służy wyłącznie do debugowania, nie uruchamia żadnego programu,
określone za pomocą przycisku RUN. Może wyświetlać nieprawidłowe wyniki, ponieważ
niektóre wartości mogą się różnić lub mogą być niedostępne podczas przebiegu symulacji.

[...]
plik_parse: czytanie „/etc/udev/rules.d/usb-keyboard.rules” jako pliku reguł
udev_rules_new: reguły używają tokenów 100572 bajtów (8381 * 12 bajtów), bufor 21523 bajtów
udev_rules_new: używany indeks tymczasowy 35380 bajtów (1769 * 20 bajtów)
udev_device_new_from_syspath: urządzenie 0x3b4d8 ma 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: gniazdo RUN: @ / 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: gniazdo RUN: / 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 = "Klawiatura zgodna z 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 = dane wejściowe: b0003v062Ap0201e0110-e0,1,2,3,4, k71,72,73,74,77,80,82,83,85,86,87,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 = add
udevadm_test: SUBSYSTEM = wejście
udevadm_test: run: '/ sbin / modprobe -b input: b0003v062Ap0201e0110-e0,1,2,3,4, k71,72,73,73,78,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,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,77,7,80,82,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 / kernel / udev / monitor'
udevadm_test: run: '/ usr / bin / xmodmap ~ / .usbXmodmap'

i

> test udevadm --action = usuń /devices/platform/ehci-omap.0/usb1/1-2/1-2.3/1-2.3:1.1/input/input10

wyjścia:

polecenie_ruchomienia: wywołanie: test
udevadm_test: wersja 151
Ten program służy wyłącznie do debugowania, nie uruchamia żadnego programu,
określone za pomocą przycisku RUN. Może wyświetlać nieprawidłowe wyniki, ponieważ
niektóre wartości mogą się różnić lub mogą być niedostępne podczas przebiegu symulacji.

[...]
plik_parse: czytanie „/etc/udev/rules.d/usb-keyboard.rules” jako pliku reguł
udev_rules_new: reguły używają tokenów 100572 bajtów (8381 * 12 bajtów), bufor 21523 bajtów
udev_rules_new: używany indeks tymczasowy 35380 bajtów (1769 * 20 bajtów)
udev_device_new_from_syspath: urządzenie 0x3b4d8 ma devpath '/devices/platform/ehci-omap.0/usb1/1-2/1-2.3/1-2.3:1.1/input/input10'
udev_rules_apply_to_event: gniazdo RUN: @ / org / freedesktop / hal / udev_event '/etc/udev/rules.d/90-hal.rules:2
udev_rules_apply_to_event: gniazdo RUN: / 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 = "Klawiatura zgodna z 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 = dane wejściowe: b0003v062Ap0201e0110-e0,1,2,3,4, k71,72,73,74,77,80,82,83,85,86,87,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 = usuń
udevadm_test: SUBSYSTEM = wejście
udevadm_test: run: 'socket: @ / org / freedesktop / hal / udev_event'
udevadm_test: run: 'socket: / org / kernel / udev / monitor'
udevadm_test: run: '/ usr / bin / xmodmap ~ / .pndXmodmap'

co wydaje się wskazywać, że powinno działać, ale nie ma nadziei, że to pomoże uzyskać odpowiedź.

Jake Aitchison
źródło

Odpowiedzi:

14

Znalazłem sposób na obejście tego, choć jest to trochę zuchwałe.

Doszedłem do tego samego dokładnego punktu dzisiaj, próbując skonfigurować dwie klawiatury z udev, setxkbmap i xinput --list i aby mogły one pracować z hotplugowaniem USB. Zamieniam klawisze, nie zmieniam układu, ale wszystko jest takie samo, gdy już zidentyfikujesz klawiaturę na hotplug i możesz warunkowo wywołać setxkbmap, powinieneś być w stanie ustawić język tylko klawiatury, którą określiłeś . Lista układów klawiatury znajduje się tutaj ls -l /usr/share/kbd/keymaps/i386/i możesz znaleźć nazwę swojego urządzenia xinput -list.

  1. Będziesz chciał zastąpić rizumuswoją nazwę użytkownika, ponieważ okazało się, że nie można tego zrobić bez wyraźnego określenia.
  2. Upewnij się, że grep na yournazwie klawiatury.
  3. Służy lsusbdo wykrywania identyfikatora sprzętu, który należy ustawić w regule udev. Moja klawiatura das wygląda takBus 002 Device 009: ID 04d9:2013 Holtek Semiconductor, Inc.

Najpierw skonfigurowałem regułę udev do automatycznego wykrywania klawiatury, tworząc regułę udev:

W pliku /etc/udev/rules.d/00-usb-keyboards.rules:

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

Mam dwa pliki ~ / bin / kbd i ~ / bin / kbd_udev. Upewnij się, że mają odpowiednie uprawnieniachmod 755 ~/bin/kbd*

~/bin/kbd_udevSkrypt zawiera:

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

Zauważysz, że wystarczy zadzwonić ~/bin/kbdw tle, aby udev mógł zakończyć proces i aktywować klawiaturę. Wewnątrz ~/bin/kbdskryptu śpimy przez sekundę, ponieważ musimy poczekać, aż klawiatura zostanie aktywowana, abyśmy mogli uzyskać identyfikator urządzenia za pomocą xinput. Aby to mam ustawić kilka zmiennych achive i wywoził je tak xinput setxkbmap może nie thier pracy: DISPLAY, XAUTHORITY, HOME, i jeden daskb_iddla mojego daskeyboard ID:

#!/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
źródło
Bardzo dziękuję za pomoc w udzieleniu odpowiedzi na moje pytanie: AskUbuntu
Sadi
Zastanawiam się, czy możesz mi pomóc dodać powiadomienie na końcu tego skryptu (np notify-send "USB Keyboard is plugged in and ready for use now." -i gtk-dialog-info -t 1000 -u normal.). Ponieważ niewiele wiem o skryptach, próbowałem wstawić go przed „fi” lub po nim, ale w obu przypadkach komunikat powiadomienia pojawiał się w kółko :-(
Sadi
Dlaczego warto ustawić OWNERdla tego urządzenia?
Limbo Peng
1
Co robi xset r rate 200 30linia? xsetnie jest dostępny w mojej instalacji Ubuntu 17.04.
kleinfreund
1
Nie mogę uruchomić xmodmap $HOME/.Xmodmapskryptu analogicznego do twojego „/ home / rizumu / bin / kbd”. Dlaczego miałoby to być?
Geremia,
4

W zależności od dystrybucji możesz już mieć regułę udev dla klawiatur w /lib/udev/rules.d/64-xorg-xkb.rules. W Ubuntu importuje / etc / default / keyboard, który ma opcje mniej więcej takie:

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

Dla mojej konfiguracji odkryłem, że ta wbudowana reguła działała po mojej niestandardowej regule udev i zastępowała moje ustawienia. Zamiast tego zmieniłem XKBOPTIONS w / etc / default / keyboard na:

XKBOPTIONS="-option ctrl:nocaps"

Aby uzyskać zachowanie „Caps Lock is Control”, chciałem na wszystkich klawiaturach.

jsha
źródło
2
Świetny pomysł! Mój działa tylkoXBKOPTIONS="ctrl:nocaps"
RasmusWL
3

Jeśli korzystasz z GNOME, musisz wyłączyć wtyczkę do zarządzania klawiaturą, aby nie zastępowała zmian w układzie.

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

Ponownie uruchom to samo polecenie, aby włączyć je zgodnie z potrzebami.

Ignacio Vazquez-Abrams
źródło
biegnę angstrem. Czy to zadziała?
Jake Aitchison
Czy używasz GNOME na Ångström?
Ignacio Vazquez-Abrams
nope im using xfce 4.6.1
Jake Aitchison
1
W moim Ubuntu 13.04 jest to dconfponiżej /org/gnome/settings-daemon/plugins/keyboard/active.
nh2
1
A polecenie dla Ubuntu 13.04 brzmi:gsettings set org.gnome.settings-daemon.plugins.keyboard active false
Sadi
3

To nie działa, bo udevi xmodmapnie ma dostępu do wyświetlacza X11. W rzeczywistości udevnawet nie wie, czy aktywne wyświetlacze X11.

  • Uwaga: wyświetlacze , liczba mnoga. Nie może używać „wyświetlacza” X11, ponieważ może istnieć więcej niż jeden. Na przykład, jeśli używasz „szybkiego przełączania użytkowników”.
grawitacja
źródło
więc jak mogę sprawić, żeby to działało?
Jake Aitchison
ktoś wie jak to naprawić?
Jake Aitchison
1
Dostałem udev do wywołania setxkbmap. Reguła udev nazywa skrypt, który stanowi tło innego skryptu (aby udev mógł wykonać). Drugi skrypt zatrzymuje się na sekundę, ustawia oczekiwane zmienne X11 i wyzwala setxkbmap. Zobacz moją odpowiedź na główne pytanie, aby uzyskać więcej informacji.
Thomas Schreiber,
@rizumu: Ahh, powodzenia w pracy z GDM.
grawity
3

Co z konfiguracją X.Org? Z Gentoo Wiki: X.Org/Input_drivers - udev :

Przykład: jeśli masz klawiaturę Logitech Access dla francuskiej części Szwajcarii, możesz użyć następujących opcji:

Plik: /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

Aby uzyskać szczegółowe wyjaśnienie, przeczytaj:

man xorg.conf

i:

man evdev

ArchWiki demonstruje użycie tej samej składni w xorg.conf, ale zauważa, że ​​„w dzisiejszych czasach powinieneś utworzyć osobny plik konfiguracyjny, taki jak /etc/X11/xorg.conf.d/90-keyboard-layouts.conf”. Korzystam z Arch i skonfigurowałem własną klawiaturę USB w istniejącym pliku /etc/X11/xorg.conf.d/vim 10-evdev.conf. Pracowałem dla mnie.

@rizumu: Clever kludge, dzięki za udostępnienie.

Casey Jones
źródło
1
Nie mam katalogu x.org.conf.d w Linux Mint 18.2
Max N
2

Aby odpowiedzieć na pytanie dotyczące dostępu do działającego ekranu, możesz wyeksportować odpowiednią zmienną DISPLAY w skrypcie, zakładając, że uprawnienia do wyświetlania są poprawnie ustawione. (w man xsetprzypadku uprawnień do wyświetlania).

W wielu zwykłych przypadkach możesz po prostu użyć export DISPLAY=:0polecenia, ponieważ jest to pierwszy ekran w systemie jednego użytkownika. Prawdopodobnie najłatwiej jest uruchomić skrypt bezpośrednio niż xmodmap, ponieważ pozwoli ci to mieć większą kontrolę nad zmiennymi środowiskowymi i resztą. (Więc zamień „/ usr / bin / xmodmap ~ / .usbXmodmap” w swojej regule na „/usr/local/bin/keyboard_plug.sh” i umieść odpowiednie polecenia w tym skrypcie wraz ze zmienną DISPLAY.)

Jak wspomniano powyżej, jednak jeśli przyjmiesz DISPLAY =: 0, możesz później napotkać problemy, jeśli masz wielu użytkowników lub wyświetlaczy. Możesz pisać skrypty, aby wykryć odpowiedni ekran, ale w takim przypadku jesteś sam (o ile dotyczy to odpowiedzi). :)

rdza i ćma
źródło
2

Myślę, że znalazłem o wiele czystszy sposób na skonfigurowanie tego, który nie wymaga specjalnego hakowania X11.

Pomysł polega na tym, że udevwykryje tylko nowe wprowadzanie z klawiatury i utworzy dowiązanie symboliczne dla każdego układu, a następnie inotifybędzie szukał nowego układu w przestrzeni użytkownika.

zasady 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"

Zgodnie z tymi regułami mam katalog w dev ( /dev/input/by-layout) do obserwowania zmian w skryptach przestrzeni użytkownika.

Skrypt przestrzeni użytkownika dla KDE

Na przykład podczas korzystania z KDE mam uruchomiony ten skrypt (automatyczny):

#!/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

Dla mnie to działa jak urok. Aby zmienić układ systemu (którego nie potrzebuję teraz), podobny skrypt, którego loadkeysmożna użyć, można zdemonizować za pomocą systemowego skryptu inicjującego.

giosh94mhz
źródło
Dzięki, uświadomiłem sobie, że mogę po prostu inotifywaituruchomić skrypt instalacyjny przy każdej zmianie /dev/input, ponieważ sam skrypt jest idempotentny.
Charlie Gorichanaz
0

Ponieważ nie mogłem zmusić hacków do działania reguł udev, napisałem mały skrypt Pythona, który używa pyudevdo monitorowania zdarzeń wejściowych.

#! /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()

Następnie używam tego pliku systemowej jednostki użytkownika, aby utrzymać go w działaniu ( 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

inotifywaitRozwiązanie z @ giosh94mhz jest trochę prostsza, a unika się zależność pyudev. Jednak z jakiegoś powodu zauważyłem, że inotifyzdarzenie nie było uruchamiane przez 10-20 sekund po podłączeniu klawiatury.

Ryan Marcus
źródło