aturan udev untuk memuat tata letak keyboard secara otomatis saat keyboard usb terpasang

22

Saya mencoba memuat tata letak keyboard baru ketika saya mencolokkan keyboard usb tetapi aturan udev saya tidak berfungsi.

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

LABEL = "usb_xmodmap_auto"
ACTION == "add", RUN + = "/ usr / bin / xmodmap ~ / .usbXmodmap"
AKSI == "hapus", RUN + = "/ usr / bin / xmodmap ~ / .pndXmodmap"

Saya telah memuat ulang aturan menggunakan:

> sudo udevadm control --reload-rules

dan dengan me-restart sistem tetapi ketika saya mencolokkan keyboard usb xmodmap asli masih dimuat dan dengan demikian tata letak keyboard salah, tetapi jika saya menjalankan perintah di terminal

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

mereka bekerja dengan baik.

semoga soneone bisa membantu.

Edit:

hanya untuk membantu saya menjalankan beberapa tes udevadm:

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

output:

run_command: calling: test
udevadm_test: versi 151
Program ini hanya untuk debugging, tidak menjalankan program apa pun,
ditentukan oleh kunci RUN. Ini mungkin menunjukkan hasil yang salah, karena
beberapa nilai mungkin berbeda, atau tidak tersedia pada simulasi.

[...]
parse_file: membaca '/etc/udev/rules.d/usb-keyboard.rules' sebagai file aturan
udev_rules_new: aturan menggunakan token 100572 byte (8381 * 12 byte), buffer 21523 byte
udev_rules_new: indeks sementara digunakan 35380 byte (1769 * 20 byte)
udev_device_new_from_syspath: perangkat 0x3b4d8 memiliki 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#
udev_rules_apply_to_event: RUN 'socket: @ / org / freedesktop / hal / udev_event' /etc/udev/rules.d/90-hal.rules:
udev_rules_apply_to_event: RUN '/ sbin / modprobe $ env {MODALIAS}' /etc/udev/rules.d/local.rules:31
udev_rules_apply_to_event: RUN 'socket: / org / kernel / udev / monitor' /etc/udev/rules.d/run.rules:
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 = / perangkat / 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 = "Keyboard yang sesuai dengan 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,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.1010, 10B, 10C, 162.166.16A, 16E, 178.179.117A, 17B, 17C, 17D, 17.18.180.180 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 = input
udevadm_test: run: '/ sbin / modprobe -b input: b0003v062Ap0201e0110-e0,1,2,3,4, k71,72,73,74,77,80,82,83,85,85,86,87,88,89,89 , 8A, 8B, 8C, 8E, 8F, 90,96,98,9B, 9C, 9E, 9F, A1, A3, A4, A5, A6, A7, A8, 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, 17D , 17F, 180.181.182.185C, 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,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 / kernel / udev / monitor'
udevadm_test: run: '/ usr / bin / xmodmap ~ / .usbXmodmap'

dan

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

output:

run_command: calling: test
udevadm_test: versi 151
Program ini hanya untuk debugging, tidak menjalankan program apa pun,
ditentukan oleh kunci RUN. Ini mungkin menunjukkan hasil yang salah, karena
beberapa nilai mungkin berbeda, atau tidak tersedia pada simulasi.

[...]
parse_file: membaca '/etc/udev/rules.d/usb-keyboard.rules' sebagai file aturan
udev_rules_new: aturan menggunakan token 100572 byte (8381 * 12 byte), buffer 21523 byte
udev_rules_new: indeks sementara digunakan 35380 byte (1769 * 20 byte)
udev_device_new_from_syspath: perangkat 0x3b4d8 memiliki 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:
udev_rules_apply_to_event: RUN 'socket: / org / kernel / udev / monitor' /etc/udev/rules.d/run.rules:
udev_rules_apply_to_event: RUN '/ usr / bin / xmodmap ~ / .pndXmodmap' /etc/udev/rules.d/usb-keyboard.rules 5-10
udevadm_test: UDEV_LOG = 6
udevadm_test: DEVPATH = / perangkat / 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 = "Keyboard yang sesuai dengan 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,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.1010, 10B, 10C, 162.166.16A, 16E, 178.179.117A, 17B, 17C, 17D, 17.18.180.180 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 = hapus
udevadm_test: SUBSYSTEM = input
udevadm_test: run: 'socket: @ / org / freedesktop / hal / udev_event'
udevadm_test: run: 'socket: / org / kernel / udev / monitor'
udevadm_test: run: '/ usr / bin / xmodmap ~ / .pndXmodmap'

yang tampaknya menunjukkan itu harus berfungsi, tetapi tidak berharap ini membantu mendapatkan jawaban.

Jake Aitchison
sumber
1
terkait .

Jawaban:

14

Saya menemukan cara untuk mengatasi hal ini, meskipun sedikit berantakan.

Saya sampai pada titik yang persis sama hari ini dalam mencoba mengatur dua keyboard dengan udev, setxkbmap, dan xinput --list dan agar mereka dapat bekerja dengan hotplugging usb. Saya bertukar tombol di sekitar, tidak mengubah tata letak, tetapi semuanya sama, setelah Anda mengidentifikasi papan ketik di hotplug dan secara kondisional dapat memanggil setxkbmap, maka Anda harus dapat mengatur bahasa hanya papan ketik yang telah Anda tentukan . Daftar tata letak keyboard dapat ditemukan di sini ls -l /usr/share/kbd/keymaps/i386/dan Anda dapat menemukan nama perangkat Anda untuk dihubungi xinput -list.

  1. Anda akan ingin mengganti rizumudengan nama pengguna Anda, karena saya menemukan itu tidak mungkin cara untuk melakukan ini tanpa eksplisit.
  2. Pastikan Anda memahami yournama keyboard.
  3. Gunakan lsusbuntuk menemukan ID Perangkat Keras yang perlu Anda atur dalam aturan udev. Keyboard das saya terlihat seperti iniBus 002 Device 009: ID 04d9:2013 Holtek Semiconductor, Inc.

Saya pertama kali mengatur aturan udev untuk autodetct keyboard adalah dengan membuat aturan udev:

Dalam file /etc/udev/rules.d/00-usb-keyboards.rules:

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

Saya memiliki dua file ~ / bin / kbd dan ~ / bin / kbd_udev. Pastikan mereka memiliki izin yang tepatchmod 755 ~/bin/kbd*

The ~/bin/kbd_udevScript berisi:

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

Dan Anda akan melihat bahwa yang dilakukannya hanyalah panggilan ~/bin/kbddi latar belakang, sehingga udev dapat menyelesaikan prosesnya dan mengaktifkan keyboard. Di dalam ~/bin/kbdscript kita tidur sebentar, karena kita perlu menunggu sampai keyboard diaktifkan sehingga kita bisa mendapatkan id perangkat menggunakan xinput. Untuk mencapai hal ini saya telah menetapkan beberapa variabel dan diekspor mereka sehingga setxkbmap XInput dapat melakukan pekerjaan mereka: DISPLAY, XAUTHORITY, HOME, dan satu daskb_iduntuk id dari daskeyboard saya:

#!/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
sumber
Terima kasih banyak telah membantu saya menjawab pertanyaan saya sendiri yaitu AskUbuntu: askubuntu.com/questions/337411/…
Sadi
Dan saya ingin tahu apakah Anda juga dapat membantu saya menambahkan pesan pemberitahuan di akhir skrip ini (misalnya notify-send "USB Keyboard is plugged in and ready for use now." -i gtk-dialog-info -t 1000 -u normal). Karena saya tidak tahu banyak tentang scripting, saya mencoba memasukkannya sebelum atau setelah "fi" tetapi dalam kedua kasus pesan notifikasi terus muncul berulang-ulang :-(
Sadi
Mengapa pengaturan OWNERuntuk perangkat ini?
Limbo Peng
1
Apa yang dilakukan xset r rate 200 30garis? xsettidak tersedia di instalasi Ubuntu 17.04 saya.
kleinfreund
1
Saya tidak dapat menjalankan xmodmap $HOME/.Xmodmapmenggunakan skrip analog dengan "/ home / rizumu / bin / kbd" Anda. Kenapa bisa begitu?
Geremia
3

Jika Anda menjalankan GNOME maka Anda harus menonaktifkan plugin manajemen keyboardnya agar tidak menimpa perubahan tata letak Anda.

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

Jalankan perintah yang sama lagi untuk mengaktifkannya sesuai keinginan.

Ignacio Vazquez-Abrams
sumber
Saya menjalankan angstrom. apakah ini akan berhasil?
Jake Aitchison
Apakah Anda menggunakan GNOME di Ångström?
Ignacio Vazquez-Abrams
nggak im menggunakan xfce 4.6.1
Jake Aitchison
1
Di Ubuntu 13.04 saya, ini ada di dconfbawah /org/gnome/settings-daemon/plugins/keyboard/active.
nh2
1
Dan perintah untuk Ubuntu 13.04 adalah:gsettings set org.gnome.settings-daemon.plugins.keyboard active false
Sadi
3

Ini tidak berfungsi karena udevdan xmodmaptidak memiliki akses ke tampilan X11 Anda. Bahkan, udevbahkan tidak tahu apakah ada yang menampilkan X11 aktif.

  • Catatan: display , jamak. Itu tidak dapat menggunakan "tampilan" X11 karena mungkin ada lebih dari satu. Misalnya, jika Anda menggunakan "perpindahan pengguna cepat".
grawity
sumber
jadi Bagaimana saya bisa membuat ini berfungsi?
Jake Aitchison
ada yang tahu bagaimana saya bisa memperbaikinya?
Jake Aitchison
1
Saya sudah mendapatkan udev untuk memanggil setxkbmap. Aturan udev memanggil skrip yang melatar belakangi skrip lain (sehingga udev dapat menyelesaikan). Script kedua berhenti sebentar, mengatur variabel X11 yang diharapkan, dan memicu setxkbmap. Lihat jawaban saya untuk pertanyaan utama untuk lebih jelasnya.
Thomas Schreiber
@rizumu: Ahh, semoga sukses membuatnya bekerja dengan GDM.
grawity
3

Bagaimana dengan konfigurasi X.Org? Dari Gentoo Wiki: X.Org/Input_drivers - udev :

Contoh: Jika Anda memiliki keyboard Logitech Access untuk bagian Prancis dari Swiss, Anda dapat menggunakan yang berikut ini:

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

Untuk penjelasan mendalam, baca:

man xorg.conf

dan:

man evdev

ArchWiki menunjukkan menggunakan sintaks yang sama di xorg.conf tetapi mencatat bahwa "saat ini Anda harus membuat file konfigurasi terpisah, seperti /etc/X11/xorg.conf.d/90-keyboard-layouts.conf". Saya menggunakan Arch dan mengkonfigurasi keyboard USB saya sendiri di /etc/X11/xorg.conf.d/vim 10-evdev.conf yang ada. Bekerja untuk saya.

@rizumu: Kludge yang pintar, terima kasih telah berbagi.

Casey Jones
sumber
1
Saya tidak memiliki direktori x.org.conf.d di Linux Mint 18.2
Max N
3

Bergantung pada distro Anda, Anda mungkin sudah memiliki aturan udev untuk keyboard di /lib/udev/rules.d/64-xorg-xkb.rules. Di Ubuntu, ini mengimpor / etc / default / keyboard, yang memiliki opsi kira-kira seperti ini:

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

Untuk pengaturan saya, saya menemukan bahwa aturan bawaan ini dijalankan setelah aturan udev kustom saya, dan mengesampingkan pengaturan saya. Alih-alih, saya mengubah XKBOPTIONS di / etc / default / keyboard menjadi:

XKBOPTIONS="-option ctrl:nocaps"

Untuk mendapatkan perilaku "Caps Lock is Control" yang saya inginkan di semua keyboard.

jsha
sumber
1
Ide yang hebat! XBKOPTIONS="ctrl:nocaps"
Milik
2

Untuk menjawab pertanyaan Anda tentang mengakses tampilan yang sedang berjalan, Anda dapat mengekspor variabel DISPLAY yang sesuai dalam skrip, dengan asumsi bahwa izin untuk tampilan diatur dengan benar. ( man xsetuntuk izin tampilan.)

Dalam banyak kasus yang biasa Anda hanya dapat export DISPLAY=:0untuk perintah, karena itulah tampilan pertama pada sistem pengguna tunggal. Mungkin paling mudah untuk menjalankan skrip daripada xmodmap secara langsung, karena ini akan memungkinkan Anda untuk memiliki kontrol lebih besar terhadap variabel lingkungan dan sisanya. (Jadi, ganti "/ usr / bin / xmodmap ~ / .usbXmodmap" dalam aturan Anda dengan "/usr/local/bin/keyboard_plug.sh" dan letakkan perintah yang sesuai dalam skrip tersebut bersama dengan variabel DISPLAY.)

Seperti yang disebutkan di atas, meskipun, jika Anda mengasumsikan DISPLAY =: 0 maka Anda mungkin mengalami masalah di kemudian hari jika Anda memiliki beberapa pengguna atau tampilan. Anda dapat menulis skrip untuk mendeteksi tampilan yang sesuai, tetapi dalam hal ini Anda melakukannya sendiri (sejauh menyangkut jawaban ini). :)

rust_and_moth
sumber
2

Saya rasa saya menemukan cara yang lebih bersih untuk mengkonfigurasi ini, yang tidak memerlukan hack X11 khusus.

Gagasan di balik ini adalah bahwa udevhanya akan mendeteksi input keyboard baru dan membuat symlink untuk setiap tata letak, kemudian inotifyakan melihat tata letak baru di userspace.

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

Dengan aturan ini, saya memiliki direktori di bawah dev ( /dev/input/by-layout) untuk mengawasi perubahan skrip userspace.

Skrip Userspace untuk KDE

Misalnya, ketika menggunakan KDE saya menjalankan skrip ini (otomatis):

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

Ini bekerja seperti pesona bagiku. Untuk mengubah tata letak sistem (yang tidak saya butuhkan saat ini), skrip serupa yang digunakan loadkeysdapat di-demonisasi menggunakan skrip init sistem.

giosh94mhz
sumber
Terima kasih, ini membuat saya sadar bahwa saya hanya dapat menggunakan inotifywaituntuk menjalankan skrip pengaturan pada perubahan apa pun /dev/input, karena skrip itu sendiri idempoten.
Charlie Gorichanaz
0

Karena saya tidak bisa membuat peretasan untuk membuat aturan udev bekerja, saya menulis skrip Python kecil pyudevuntuk memantau masukan acara.

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

Saya kemudian menggunakan file unit pengguna systemd ini untuk membuatnya tetap berjalan ( 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

The inotifywaitsolusi dari @ giosh94mhz adalah sedikit lebih sederhana, dan menghindari ketergantungan pada pyudev. Namun, untuk beberapa alasan saya menemukan inotifyacara tersebut tidak dipicu selama 10-20 detik setelah keyboard saya terhubung.

Ryan Marcus
sumber