Map scancodes to keycodes

出自 Arch Linux 中文维基

該頁面假定您已閱讀 Extra keyboard keys ,它提供了更多的內容。

將「掃描碼」映射為「鍵位碼」的動作,要比 Xorg 和 Linux 控制台更接近底層,所以對這個映射的更改在兩者中均有效。

[1][2][3]

將「掃描碼」映射到「鍵位碼」方式有兩種:

首選方法是使用 「udev」,因為它使用硬件信息(這是一個非常可靠的來源)來選擇數據庫中的鍵盤型號。如果能在數據庫中找到鍵盤型號,則可以「開箱即用」地識別您的按鍵。

確定掃描碼[編輯 | 編輯原始碼]

您需要知道要重新映射的鍵的「掃描代碼」。詳情請見Keyboard input#Identifying scancodes

使用 udev[編輯 | 編輯原始碼]

udev提供了一個稱為"hwdb"的內置函數,用於維護 /etc/udev/hwdb.bin 中的硬件數據庫索引。 數據庫是從位於/usr/lib/udev/hwdb.d//run/udev/hwdb.d//etc/udev/hwdb.d/ 目錄中的擴展名為.hwdb的文件編譯而成的。 默認的 "掃描碼到鍵碼" 映射文件是 /usr/lib/udev/hwdb.d/60-keyboard.hwdb 。 有關詳細信息,請參見udev(7)

注意: 從systemd 220開始,udev ABI進行了更改。 使用自定義udev hwdb規則的用户應根據新的ABI更新它們

.hwdb 文件可以包含不同鍵盤的多個映射塊,也可以將一個塊應用於多個鍵盤。 evdev: 前綴用於將塊與硬件進行匹配,支持以下硬件匹配:

  • USB內核模式標識的通用輸入設備(也包括USB鍵盤):
evdev:input:b<bus_id>v<vendor_id>p<product_id>e<version_id>-<modalias> 

其中 <vendor_id>, <product_id><version_id> 是 4位十六進制大寫(不夠4位在前面補0)的供應商,產品和版本ID ( 你可以通過運行lsusb 命令來得到它們), <modalias> 是描述設備功能的任意長度的輸入模態 (input-modalias). <bus_id> 是4位數的十六進制總線ID,對於USB設備,應為0003。<bus_id> 可能的值在 /usr/include/linux/input.h 中定義 (你可以運行 awk '/BUS_/ {print $2, $3}' /usr/include/linux/input.h 得到一個列表).

evtest或者 cat /proc/bus/input/devices 可以一次性得到<bus_id>、<vendor_id>、 <product_id> 和 <version_id>

很多時候可以不用那麼精確,就可以用 *來作為通配符。

  • AT鍵盤DMI數據匹配:
evdev:atkbd:dmi:bvn*:bvr*:bd*:svn<vendor>:pn<product>:pvr*

其中 <vendor><product> 是由內核 DMI Modalias 導出的固件提供的字符串。

  • 輸入驅動程序設備名稱和DMI數據匹配:
evdev:name:<input device name>:dmi:bvn*:bvr*:bd*:svn<vendor>:pn*

其中 <input_device_name> 是驅動程序指定的名稱設備 ,<vendor> 是由內核DMI modalias導出的固件提供的字符串。

塊主體中每一行的格式為 KEYBOARD_KEY_<scancode>=<keycode>. <scancode> 的值是十六進制的,但是沒有前導0x(即,是a0而不是0xa0), 而 <keycode> 的值是小寫的鍵名名稱字符串,就像在/usr/include/linux/input-event-codes.h中列的一樣(請參閱KEY_<KEYCODE> 變量),[4] 處有一個排序列表。注意不能在<keycode>中指定十進制值。

注意: 用root身份運行evemu-describe來獲取 這個設備(要自定義hwdb 規則的設備)的標識符, 該實用程序由 evemu 軟件包提供。 通過以root用户身份運行 evtest 這個設備(要自定義hwdb 規則的設備)的標識符以及要使用的按鍵的掃描碼。 該實用程序由evtest軟件包提供。

自定義hwdb的示例[編輯 | 編輯原始碼]

示例hwdb文件將匹配所有AT鍵盤:

/etc/udev/hwdb.d/90-custom-keyboard.hwdb
evdev:atkbd:dmi:bvn*:bvr*:bd*:svn*:pn*:pvr*
 KEYBOARD_KEY_10=suspend
 KEYBOARD_KEY_a0=search

這是在筆記本電腦和USB鍵盤上重新綁定修飾符(modifiers)的示例:

/etc/udev/hwdb.d/10-my-modifiers.hwdb
evdev:input:b0003v05AFp8277* # 在Kensington Slim Type USB(使用旧的ABI)上进行了测试
 KEYBOARD_KEY_70039=leftalt  # 将capslock绑定到leftalt
 KEYBOARD_KEY_700e2=leftctrl # 将leftalt绑定到leftctrl

evdev:atkbd:dmi:*            # 内置键盘:匹配所有AT键盘
 KEYBOARD_KEY_3a=leftalt     # 将capslock绑定到leftalt
 KEYBOARD_KEY_38=leftctrl    # 将leftalt绑定到leftctrl
提示:上面的綁定的含義 A綁定到B,是指:在物理上按下A按鍵,計算機輸入B按鍵

要阻止 Sleep鍵,請將其綁定到 "reserved" 關鍵字。 或者,您可以使用 "unknown" 將其映射到 NoSymbol鍵。 例如:

/etc/udev/hwdb.d/90-block-sleep.hwdb
evdev:input:b0003v03F0p020C* # hp 5308 keyboard controller
 KEYBOARD_KEY_10082=reserved

更新硬件數據庫索引[編輯 | 編輯原始碼]

更改配置文件後,需要重建硬件數據庫索引 hwdb.bin

  • 通過運行一下命令手動更新 hwdb.bin
# systemd-hwdb update

本文內容或本節內容已經過期。

原因: ConditionNeedsUpdate=/etc seems to be commented out by default in systemd-hwdb-update.service (checked in systemd 232). (在Talk:Map scancodes to keycodes討論)

本文或本章節的事實準確性存在爭議。

原因: Do not edit in /usr/lib/, use systemctl edit.(在 Talk:Map scancodes to keycodes 中討論)


  • 通過註釋掉systemd-hwdb-update.service 中的ConditionNeedsUpdate,在每次重新啟動時自動更新。
/usr/lib/systemd/system/systemd-hwdb-update.service
#  该文件是systemd的一部分。
.
.
#ConditionNeedsUpdate=/etc
.
.

systemd-hwdb-update.service完成加載後,systemd-trigger.service將從hwdb.bin重新加載更改。

Systemd的每次升級中,安裝腳本都通過以root用户身份運行udevadm hwdb --update來重建hwdb.bin,因此我們不需要關心它 。

重新加載硬件數據庫索引[編輯 | 編輯原始碼]

內核在啟動過程中加載hwdb.bin,重新啟動系統將保證加載更新後的hwdb.bin

使用 udevadm,可以通過運行下面命令來從更新後的hwdb.bin加載新的鍵映射。

# udevadm trigger

Be aware that with udevadm only added or changed key mapping are loaded so if we delete a mapping from the config file, rebuild hwdb.bin and run udevadm trigger as the root user, then the deleted mapping still kept by the kernel, at least until a reboot. 請注意,使用 udevadm 僅加載已添加或更改的鍵映射,因此,如果我們從配置文件中刪除映射,重建 hwdb.bin 並以root用户身份運行 udevadm trigger ,那麼刪除的映射仍將保留在內核中,直到重新啟動為止。

查詢數據庫[編輯 | 編輯原始碼]

您可以通過按鍵或運行 udevadm info 來檢查配置是否已加載。 對於上面示例中的USB鍵盤,這將輸出我們配置的映射,如下所示:

# udevadm info /dev/input/by-path/*-usb-*-kbd | grep KEYBOARD_KEY
E: KEYBOARD_KEY_70039=leftalt
E: KEYBOARD_KEY_700e2=leftctrl

使用setkeycodes[編輯 | 編輯原始碼]

setkeycodes 是一個將 scancodes-to-keycodes 映射表加載到Linux內核中的工具。 它的用法是:

# setkeycodes scancode keycode ...

可以一次指定多個對。 掃描碼(Scancodes) 以十六進制給出, 鍵位碼 以十進制給出。

注意: 顯然, setkeycodes 不適用於USB鍵盤(Linux 3.14.44-1-lts):
# setkeycodes 45 30     # 将NumLock(0x45)绑定到AT键盘上的KEY_A(30)
(successful)
# setkeycodes 70053 30  # 将NumLock(0x70053)绑定到USB键盘上的KEY_A(30)
KDSETKEYCODE: Invalid argument
failed to set scancode 620d3 to keycode 31

參閱[編輯 | 編輯原始碼]