Linux 永久更改鍵盤設定

Allen Chang
Jul 14, 2018 · 11 min read

前言

最近跟同事借了一把Filco 60%茶軸來玩,他有特別的雙fn設計,同時按 fn和; 就等於backspace,fn和s/d/e/f 就變成方向鍵,手腕都不用動,爽爽的。

可是一把要四千五,而且s/d/e/f跟Vim的h/j/k/l不一樣,用起來還是有點不太習慣。

於是,經過幾天的hacking,我終於可以直接改變Linux內建的鍵盤設定,讓筆電鍵盤也可以像Filco的fn一樣。

第一篇Medium,就這麼誕生啦!!

一、Xmodmap

Xmodmap是比較舊、比較low-level的鍵盤設定工具,不過設定相對簡單,容易做一些基本的按鍵置換(比如換Capslock跟Control的位置),因此在各大網站也常常被提到。

首先可以利用 xev 指令看每個按鍵的keycode:

$ xev
KeyPress event, serial 36, synthetic NO, window 0x3e00001,
root 0x86, subw 0x0, time 890946390, (803,237), root:(804,294),
state 0x2, keycode 66 (keysym 0xffe3, Control_L), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
KeyPress event, serial 36, synthetic NO, window 0x3e00001,
root 0x86, subw 0x0, time 891083183, (793,9), root:(794,66),
state 0x0, keycode 37 (keysym 0xffe5, Caps_Lock), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False

然後用簡單的指令:

xmodmap "keycode 37 = Caps_Lock"
xmodmap "keycode 66 = Control_L"

就可以交換Capslock跟左Control了。每次登入都要要重新輸入有點麻煩,可以把設定放在~/.Xmodmap裡面:

remove Lock = Caps_Lock
remove Control = Control_L
keysym Control_L = Caps_Lock
keysym Caps_Lock = Control_L
add Lock = Caps_Lock
add Control = Control_L

然後把xmodmap ~/.Xmodmap放到開機會執行的設定檔(~/.bashrc~.zshrc等等),登入時就會自動執行。想復原的話,可以用setxkbmap -option來重置。

這是我的~/.Xmodmap設定:

 remove Lock = Caps_Lock
remove Control = Control_R
keysym Control_R = Caps_Lock
keysym Caps_Lock = Control_R
add Lock = Caps_Lock
add Control = Control_R

keycode 66 = Mode_switch
keysym h = h H Left
keysym l = l L Right
keysym k = k K Up
keysym j = j J Down
keysym u = u U Prior
keysym i = i I Home
keysym o = o O End
keysym p = p P Next
keysym d = d D Return
keysym f = f F Return
keysym semicolon = semicolon colon BackSpace

以上設定把沒有用的Capslock移到更沒用的右Control,然後把原本的Capslock改成Mode_switch(有點類似fn,有時候也叫AltGr)所以同時按Capslock+h/l/k/j/u/i/o/p/d/f/;就會變成上面keysym第三格的Left/Right/Up/Down/PageUp/Home/End/PageDown/Enter/BackSpace,這下連按Enter都不用動手腕了,比Filco預設的還方便!

(你可能注意到了,keysym定義第一個是正常使用的按鍵,第二個就是按Shift的時候會出現的字,這是Level的概念,之後會解釋。你也可以把Shift+a定義成B,或任何輸出)

使用Xmodmap的優點是簡單,不過缺點是如果系統休眠或切換layout(比如說換到新酷音),就得再執行一次xmodmap ~/.Xmodmap,非常困擾,也很難解決。 有人寫了一個python script自動幫忙執行這個指令,可以參考看看。

二、X keyboard extension (XKB)

一直沒辦法解決換輸入法時Xmodmap會被重設的問題,讓我困擾了許久,最後在這裡找到了以XKB的根本解法。

XKB是現在Linux使用的鍵盤設定,觀念規則相當複雜,教學也不是很多,可以參考Arc Linux的Wiki,或 Chunlin-Li的中文介紹。XKB的設定檔都在/usr/share/X11/xkb底下:

$ ls /usr/share/X11/xkb
compat geometry keycodes rules symbols types

其中

  • keycodes是定義每個按鍵的代號,比如說<AD01>通常是鍵盤上Q的位置
  • symbols是定義每個按鍵實際按下去的動作,比如說按下鍵盤上的Q,通常會打出q
  • rules則是一些系統存取解釋檔,比如說設定鍵盤layout的時候可以選取各種語言等等

在這邊我們主要要改的是symbols。在symbols下面可以看到各種語言的設定,他們彼此可能具有繼承的關係,以一般常見的英文鍵盤`us`為例,basic定義了基本的鍵盤(繼承最基本的定義,pc):

default  partial alphanumeric_keys modifier_keys
xkb_symbols "basic" {

name[Group1]= "English (US)";
key <TLDE> { [ grave, asciitilde ] };
key <AE01> { [ 1, exclam ] };
key <AE02> { [ 2, at ] };
key <AE03> { [ 3, numbersign ] };
key <AE04> { [ 4, dollar ] };
key <AE05> { [ 5, percent ] };
key <AE06> { [ 6, asciicircum ] };
key <AE07> { [ 7, ampersand ] };
key <AE08> { [ 8, asterisk ] };
key <AE09> { [ 9, parenleft ] };
key <AE10> { [ 0, parenright ] };
key <AE11> { [ minus, underscore ] };
key <AE12> { [ equal, plus ] };
(...)

但由於每個地區的英文鍵盤不盡相同,對每個鍵盤都會有些微調的設定,比如說同樣在us檔裡面的euro,就是繼承了us(basic)

partial alphanumeric_keys
xkb_symbols "euro" {

include "us(basic)"
name[Group1]= "English (US, with euro on 5)";

include "eurosign(5)"

include "level3(ralt_switch)"
};
各種英文鍵盤layout

可以利用setxkbmap -print -verbose 10來看目前的設定。

而我們也可以自己定義新的XKB,甚至可以改icon,這裡有詳細的教學。

自己新增的XY鍵盤

不過我自己繼承us(basic)出了一些問題,後來就直接改us(basic)的設定。這並不是一個最好的辦法,在電腦更新的時候可能會被洗掉,若要這麼做建議先備份到GitHub。

以下是我對/usr/share/X11/xkb/symbols/us的更改(須以sudo權限):

default  partial alphanumeric_keys modifier_keys
xkb_symbols "basic" {

name[Group1]= "English (US)";

key.type = "ONE_LEVEL";
key <CAPS> { [ ISO_Level3_Shift ] };
modifier_map Mod5 { ISO_Level3_Shift };

key <RCTL> { [ Caps_Lock ] };

key.type = "THREE_LEVEL";
(...)
key <AD08> { [ i, I, Home ] };
key <AD09> { [ o, O, End ] };
(...)
key <AC03> { [ d, D, Return ] };
key <AC04> { [ f, F, Return ] };
key <AC05> { [ g, G ] };
key <AC06> { [ h, H, Left ] };
key <AC07> { [ j, J, Down ] };
key <AC08> { [ k, K, Up ] };
key <AC09> { [ l, L, Right ] };
key <AC10> { [ semicolon, colon, BackSpace ] };
(...)
key <AB07> { [ m, M, Prior ] };
key <AB08> { [ comma, less, Next ] };
(...)
};
(...)

基本上就是跟先前Xmodmap一樣,把Capsloack+h/j/k/l…改成各種快捷鍵。其中:

  • key.type = “THREE_LEVEL”;定義了下面的按鍵都有三種模式(一般/按shift/按Mode_switch)
  • ISO_Level3_Shift相當於先前提到的Mode_switch,一種modifier,是level3(Shift就是ISO_Level2_Shift,也可以定義更高的level)
  • Modifiers不會受到Shfit改變行為,如ctrl/alt/enter/backspace等等
  • 在[]內的是一個group,你也可以設定多個group,然後設定按鍵在這些group之間切換

改完之後執行sudo dpkg-reconfigure xkb-data清空XKB的cache,再用setxkbmap us設定只用US layout,切換輸入法應該就會生效了。因為是直接更改default的設定,有問題可能會讓你的鍵盤不能正常運作,改的時候千萬要小心。若沒把握,可以先這篇的教學,設定額外的鍵盤,不會影響到US的設定。

使用XKB的好處是可以永久改變鍵盤設定,不受切換輸入法(在新酷音也可以用!)及休眠的影響,並且可以做複雜的改變(定義多種Level及Group等等);缺點是規則繁多,要花時間理解,且不小心可能會讓鍵盤不能正常運作。

三、XCAPE

XCAPE是一個有趣的套件,可以讓上面提到的Modifiers有一般按鍵的功能。

安裝完後執行xcape -e ‘ISO_Level3_Shift=Escape’,可以讓被定義成ISO_Level3_Shift的鍵(就是我在XKB US設訂的Capslock)有ESC的功能,這樣一來在Vim insert mode的時候只要單按Capslock就可以跳出insert mode了!!而原本設定的Capsloack+h/j/k/l…的改變也不受影響,切換輸入法也一樣有用。

總結

以往不太注意自己的打字習慣,這一年來常常因為coding手掌肌腱發炎,最近才開始慢慢調整。經過漫長的爬文獻&try-and-error,終於把鍵盤設定好啦!有種洗出+7鍵盤的感覺XD,總算可以開始認真寫code了~

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store