# Linux 鍵盤按鍵重新定義 (Keyboard Remapping) 在windows使用無線鍵盤時,為了支援特殊功能(ex.自定義巨集、開啟特殊程式等),鍵盤製造商通常會將按鍵映射至非不常用的鍵,再以驅動程式去觸發特定的功能。但是,通常製造商並不會特地再為Linux寫個驅動程式。因此,使用者在轉入Linux後,有可能會遇到一些按鍵功能錯亂的問題。 ## 查詢鍵盤鍵號 * 在 terminal 輸入 `sudo apt install evtest` 安裝測試軟體 * 在 terminal 輸入 `sudo evtest` 開始程式 ( 需要 sudo 權限 ): ```shell ❯ sudo evtest No device specified, trying to scan all of /dev/input/event* Available devices: /dev/input/event0: Lid Switch /dev/input/event1: Sleep Button /dev/input/event2: Power Button /dev/input/event3: Power Button /dev/input/event4: AT Translated Set 2 keyboard /dev/input/event5: SynPS/2 Synaptics TouchPad /dev/input/event6: MSI WMI hotkeys /dev/input/event7: Video Bus /dev/input/event8: Video Bus /dev/input/event9: HDA Intel PCH Mic /dev/input/event10: HDA Intel PCH Headphone /dev/input/event11: HDA Intel PCH HDMI/DP,pcm=3 /dev/input/event12: HDA Intel PCH HDMI/DP,pcm=7 /dev/input/event13: HDA Intel PCH HDMI/DP,pcm=8 /dev/input/event14: HDA Intel PCH HDMI/DP,pcm=9 /dev/input/event15: HDA Intel PCH HDMI/DP,pcm=10 /dev/input/event16: Smart Smart Wireless Device /dev/input/event17: BisonCam, NB Pro: BisonCam, NB /dev/input/event18: Logitech M585/M590 /dev/input/event19: Logitech K370s/K375s /dev/input/event20: Logitech K370s/K375s /dev/input/event21: Smart Smart Wireless Device Select the device event number [0-21]: ``` 輸入後,會列出所有電腦連接的設備,選擇要檢測的裝置代碼。以本次為例,外接鍵盤的代號為16,因此輸入16並按下Enter繼續。 ```shell Input driver version is 1.0.1 Input device ID: bus 0x3 vendor 0x5ac product 0x24f version 0x101 Input device name: "Smart Smart Wireless Device" Supported events: Event type 0 (EV_SYN) Event type 1 (EV_KEY) Event code 1 (KEY_ESC) Event code 2 (KEY_1) Event code 3 (KEY_2) Event code 4 (KEY_3) Event code 5 (KEY_4) Event code 6 (KEY_5) Event code 7 (KEY_6) Event code 8 (KEY_7) Event code 9 (KEY_8) ... (許多該裝置接受的功能) Properties: Testing ... (interrupt to exit) ``` 需要注意 **device ID**,在之後按鍵映射會需要裝置資訊 > Input device ID: bus 0x3 vendor 0x5ac product 0x24f version 0x101 之後,按下按鍵後,即會顯示觸發的事件: ```shell Testing ... (interrupt to exit) Event: time 1645019936.697282, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0 Event: time 1645019936.697282, -------------- SYN_REPORT ------------ Event: time 1645019943.306744, type 1 (EV_KEY), code 224 (KEY_BRIGHTNESSDOWN), value 1 Event: time 1645019943.306744, -------------- SYN_REPORT ------------ Event: time 1645019943.388729, type 1 (EV_KEY), code 224 (KEY_BRIGHTNESSDOWN), value 0 Event: time 1645019943.388729, -------------- SYN_REPORT ------------ Event: time 1645019945.955961, type 1 (EV_KEY), code 225 (KEY_BRIGHTNESSUP), value 1 Event: time 1645019945.955961, -------------- SYN_REPORT ------------ Event: time 1645019946.040973, type 1 (EV_KEY), code 225 (KEY_BRIGHTNESSUP), value 0 Event: time 1645019946.040973, -------------- SYN_REPORT ------------ Event: time 1645019947.686291, type 1 (EV_KEY), code 120 (KEY_SCALE), value 1 Event: time 1645019947.686291, -------------- SYN_REPORT ------------ Event: time 1645019947.777109, type 1 (EV_KEY), code 120 (KEY_SCALE), value 0 Event: time 1645019947.777109, -------------- SYN_REPORT ------------ Event: time 1645019948.371157, type 1 (EV_KEY), code 204 (KEY_DASHBOARD), value 1 Event: time 1645019948.371157, -------------- SYN_REPORT ------------ Event: time 1645019948.464234, type 1 (EV_KEY), code 204 (KEY_DASHBOARD), value 0 Event: time 1645019948.464234, -------------- SYN_REPORT ------------ Event: time 1645019948.996276, type 1 (EV_KEY), code 229 (KEY_KBDILLUMDOWN), value 1 Event: time 1645019948.996276, -------------- SYN_REPORT ------------ Event: time 1645019949.059168, type 1 (EV_KEY), code 229 (KEY_KBDILLUMDOWN), value 0 Event: time 1645019949.059168, -------------- SYN_REPORT ------------ Event: time 1645019949.566315, type 1 (EV_KEY), code 230 (KEY_KBDILLUMUP), value 1 Event: time 1645019949.566315, -------------- SYN_REPORT ------------ Event: time 1645019949.626316, type 1 (EV_KEY), code 230 (KEY_KBDILLUMUP), value 0 Event: time 1645019949.626316, -------------- SYN_REPORT ------------ Event: time 1645019950.193237, type 1 (EV_KEY), code 165 (KEY_PREVIOUSSONG), value 1 Event: time 1645019950.193237, -------------- SYN_REPORT ------------ Event: time 1645019950.250342, type 1 (EV_KEY), code 165 (KEY_PREVIOUSSONG), value 0 Event: time 1645019950.250342, -------------- SYN_REPORT ------------ Event: time 1645019951.013508, type 1 (EV_KEY), code 164 (KEY_PLAYPAUSE), value 1 Event: time 1645019951.013508, -------------- SYN_REPORT ------------ Event: time 1645019951.107293, type 1 (EV_KEY), code 164 (KEY_PLAYPAUSE), value 0 Event: time 1645019951.107293, -------------- SYN_REPORT ------------ Event: time 1645019951.978592, type 1 (EV_KEY), code 163 (KEY_NEXTSONG), value 1 Event: time 1645019951.978592, -------------- SYN_REPORT ------------ Event: time 1645019952.101364, type 1 (EV_KEY), code 163 (KEY_NEXTSONG), value 0 Event: time 1645019952.101364, -------------- SYN_REPORT ------------ Event: time 1645019952.736541, type 1 (EV_KEY), code 113 (KEY_MUTE), value 1 Event: time 1645019952.736541, -------------- SYN_REPORT ------------ Event: time 1645019952.830548, type 1 (EV_KEY), code 113 (KEY_MUTE), value 0 Event: time 1645019952.830548, -------------- SYN_REPORT ------------ Event: time 1645019953.596707, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 1 Event: time 1645019953.596707, -------------- SYN_REPORT ------------ Event: time 1645019953.687521, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 0 Event: time 1645019953.687521, -------------- SYN_REPORT ------------ Event: time 1645019955.750886, type 1 (EV_KEY), code 115 (KEY_VOLUMEUP), value 1 Event: time 1645019955.750886, -------------- SYN_REPORT ------------ Event: time 1645019955.835668, type 1 (EV_KEY), code 115 (KEY_VOLUMEUP), value 0 Event: time 1645019955.835668, -------------- SYN_REPORT ------------ Event: time 1645019970.354675, type 4 (EV_MSC), code 4 (MSC_SCAN), value 700e0 Event: time 1645019970.354675, type 1 (EV_KEY), code 29 (KEY_LEFTCTRL), value 1 Event: time 1645019970.354675, -------------- SYN_REPORT ------------ Event: time 1645019970.482813, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70006 Event: time 1645019970.482813, type 1 (EV_KEY), code 46 (KEY_C), value 1 Event: time 1645019970.482813, -------------- SYN_REPORT ------------ ``` 以下列事件為例: > Event: time 1645019970.482813, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70006 需要注意的是 **scan code** (0x70006),及 **key code** (KEY_C 中的 C),若想知道所有的 key code ,可以至`/usr/include/linux/input-event-codes.h`查詢。 >If evtest does not show any events even though the device is being used, the device may be grabbed by a process (EVIOCGRAB). This is usually the case when debugging a synaptics device from within X. VT switching to a TTY or shutting down the X server terminates this grab and synaptics devices can be debugged. > > The following command shows the processes with an open file descriptor on the device: > > `fuser -v /dev/input/eventX` ## 重新映射按鍵(hwdb & udev) ``` # 90-custom-keyboard.hwdb ## AT keyboard # evdev:atkbd:dmi:bvn*:bvr*:bd*:svn<vendor>:pn<product>:pvr* ## driver device name # evdev:name:<input device name>:dmi:bvn*:bvr*:bd*:svn<vendor>:pn* ## Generic input devices (also USB keyboards) identified by the usb kernel modalias evdev:input:b<bus_id>v<vendor_id>p<product_id>e<version_id>-<modalias> KEYBOARD_KEY_<scancode>=<keycode> ``` * 用文字編輯器在 `/etc/udev/hwdb.d` 建立名為 `90-custom-keyboard.hwdb` 的檔案 * 用 `evdev` 選擇要更改的設備,有下列三種格式: * `evdev:input:b<bus_id>v<vendor_id>p<product_id>e<version_id>-<modalias>` 由上述可知 > Input device ID: bus 0x3 vendor 0x5ac product 0x24f version 0x101 * `bus_id`: 0x3 * `vendor_id`: 0x5ac * `product_id`: 0x24f * `version`: 0x101 因此值為 `evdev:input:b0003v05ACp024Fe0101` :warning: id 值須為 **四位數、16進制、英文大寫** * `evdev:name:<input device name>:dmi:bvn*:bvr*:bd*:svn<vendor>:pn*` 由上述可知 > Input device name: "Smart Smart Wireless Device" * `input device name`: Smart Smart Wireless Device 因此值為 `evdev:name:Smart Smart Wireless Device` * `evdev:atkbd:dmi:bvn*:bvr*:bd*:svn*:pn*:pvr*` 此指令為AT鍵盤使用 * 輸入要更改的scancode及對應的keycode ## 更新鍵盤映射表 * 在 Terminal 下 `systemd-hwdb update` 指令即可更新。 * reboot ## 參考 [man hwdb](http://manpages.ubuntu.com/manpages/bionic/zh_TW/man7/hwdb.7.html) [Remap keys for specific device on ubuntu](https://madoshakalaka.github.io/2019/09/25/remap-keys-for-specific-device-on-ubuntu.html) [Remap keyboard keys in GNU/Linux](https://www.rigacci.org/wiki/doku.php/doc/appunti/linux/sa/remap_keyboard_keys) [Linux keymapping with udev hwdb](https://yulistic.gitlab.io/2017/12/linux-keymapping-with-udev-hwdb/) [Map scancodes to keycodes (简体中文)](https://wiki.archlinux.org/title/Map_scancodes_to_keycodes_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)) [ArchLinux 鍵盤對映:交換 CapsLock 和 Ctrl](https://www.gushiciku.cn/pl/2hbp/zh-tw)