X keyboard extension (正體中文)

From ArchWiki
Translation Status: This article is a localized version of X keyboard extension. Last translation date: 2020-09-30. You can help to synchronize the translation, if there were changes in the English version.

這個 X keyboard extension, or XKB, 定義在X視窗中鍵盤碼被處理的方法,且提供存取內部轉譯表。他是在X中允許使用多重鍵盤規劃的基本機制。

這篇文章描述如何修改與建立鍵盤佈局。如果你正尋找如何設定你的鍵盤,看Xorg/Keyboard configuration

預防措施與準備 Precautions and preparations

在X session連線中運用XKB關閉某些鍵盤上的按鍵很簡單。先確定你有辦法不使用你的鍵盤下終止X連線。

儘管機率低,改變XKB設定可能掛起或損害X伺服器。確定你可以處理他。有某些方法去執行 killall X 或遠端重開機會是好主意。

停止 xxkb 或任何規劃切換程式。 xxkb積極的改變XKB狀態,除錯兩者於同時非好主意。

獲得並設定XKB規劃

使用 rules 資料夾規則資料

看着 /usr/share/X11/xkb/rules/ 裡面的*.lst檔案或XKB Homepage以獲得怎麼設定rules檔的想法。你自定的設定可以可以運行在/etc/X11/xorg.conf.d/

例如有可能想重新規劃他的 Caps LockEscape鍵:

90-custom-kbd.conf
Section "InputClass"
    Identifier "keyboard defaults"
    MatchIsKeyboard "on"

    Option "XKbOptions" "caps:escape"
EndSection

使用按鍵規劃

使用 xkbcomp(1) (package xorg-xkbcomp) 去處理XKB資料。要獲得目前的設定,執行

   xkbcomp $DISPLAY output.xkb

要上傳資料回伺服器,執行

   xkbcomp input.xkb $DISPLAY

注意下沒有$DISPLAY參數時xkbcomp將試著去編譯.xkb檔案進入.xkm檔(多數項目沒用),而沒有上傳任何東西到伺服器上。但是這將會檢查語法及回報錯誤。

一旦佈局完成,存檔案成 ~/.Xkeymap 並讓 ~/.xinitrc 在啟動時讀取他:

   test -f ~/.Xkeymap && xkbcomp ~/.Xkeymap $DISPLAY

實際檔案名稱不重要。注意下不像系統範圍的設定會經由xorg.conf,這是每位使用者按鍵規劃。 還有,當X在運行時改變XKB設定也沒問題。

XKB 基本訊息

XKB核心是有些單純,但必須有某些概念他如何運作才開始動手按鍵規劃。

工具與定值

使用xev (package xorg-xev) 去獲得keycodes且去檢查你的按鍵規劃運作。

$ xev -event keyboard
   KeyPress event, serial 45, synthetic NO, window 0x2200001,
       root 0xad, subw 0x0, time 183176240, (796,109), root:(867,413),
       state 0x1, keycode 21 (keysym 0x2b, plus), same_screen YES,
       XLookupString gives 1 bytes: (2b) "+"
       XmbLookupString gives 1 bytes: (2b) "+"
       XFilterEvent returns: False

注意鍵碼21 keycode 21,狀態值(state) 0x1 與 按鍵象徵(keysym) 0x2b 又叫 plus 加號。keycode 21 是輸入裝置提供給 X 的,通常為某種排序的實體按鍵索引值。 狀態值(state) 表示修飾鍵(modifier keys),0x01是Shift鍵。 X隨狀態值一起送鍵碼給應用程式,以XKeyEvent(3)架構。 按鍵象徵與相對應字串乃從屬端程式XLookupString(3)使用及隨附。

在狀態欄位這些位元有預定義名稱: Shift, Lock, Control, Mod1, Mod2, Mod3, Mod4 and Mod5, 由低至高。 由此,Ctrl+Shift為 0x05,其餘如此。(羅技k120鍵盤 狀態值 0x11 Shift按下, 0x14 Control按下, 0x15 Ctrl+Shift 按下, 0x18 Alt 按下, 0x19 Alt+ Shift 按下, 0x1c Alt+Ctrl 按下, 0x1d Ctrl+Alt+Shift 按下)。從屬端應用程式通常僅檢查他們需要的位元,故應用程式以一般鍵盤輸入時,Ctrl+按鍵的快捷鍵鍵通常沒有區別於狀態值 ControlControl+Mod3

按鍵象徵也是數值型,他們多數有名字,聲明於 /usr/include/X11/keysymdef.h 隨着 KP_ 前綴。然而,那數值是從屬端實際接收。按鍵象徵唯當應用程式預期特定值才重要; 一般就像這些按鍵 方向鍵、輸入鍵、退格鍵、F開頭功能鍵(F1~Fxx)、及各式熱鍵。對其他的按鍵,特定字串被使用。

鍵碼轉譯

XKB通常工作在XLookupString階段,根據他的內部狀態轉換輸入鍵碼(keycode)成按鍵象徵(keysym),也就是群組(group)及狀態(state)值:

   (keycode, group, state) → keysym

群組通常代表"規劃佈局", 如同 美式-英文佈局 US-English, 法式-AZERTY佈局 French-AZERTY, 俄羅斯 Russian, 希臘 Greek 等等。 最多可以有4群組。

內部中,轉譯涉及額外步驟:

   (keycode [, group]) → type
   (state, type) → level
   (keycode, group, level) → S[keycode][group][level]

隨著 S 的是轉譯表 (實際上叫做 xkb_symbols, 參考以下敘述).

類別Type被用來告知哪個修飾鍵影響哪個按鍵;特別在這是個方法來減少設定按鍵 S 的第三位階。 例如,典型的字母數字鍵僅僅被 Shift 影響,所以他的類別被設爲 TWO_LEVEL,且

   (state, TWO_LEVEL) → level = ((state >> 0) & 0x01) = state & 0x01

level為0或1其中之一。因此會是S[keycode][0..4][0..1] 而不是 S[keycode][0..4][0..256]

按鍵象徵與狀態值

在X術語中,aCtrl+a意為同樣按鍵象徵但不同狀態,不過aA為不同按鍵象徵。

通常這是XKB排程提供不同按鍵象徵,可是狀態值隨後被個別應用程式處理。

同樣,狀態值在XKB中有些延遲作用,也因此,你必須讓 狀態值設定優先權給按下但按鍵

範例: Ctrl+h 可以設定成像 backspace 在 rxvt 中(應用程式中設定)。這設定法下 rxvt 將收到按鍵象徵 hControl 位元組以狀態值形式,且這值將明顯不同於 Backspace 的按鍵象徵。或者,XKB可以被用於 Ctrl+h 結合產生 Backspace 按鍵象徵,以 Control 位元組;在這案例中, rxwt將看不到任何差異在實體 Backspace鍵及 hCtrl一起按下時。 使 Ctrl+h 組合鍵產生 Backspace 按鍵象徵卻沒有Control位元組是XKB的任務,但想實現 Control+Backspace 很困難。

觸發動作 Actions

按鍵象徵從上層表中獲得時可以同時觸發某些動作:

   (keysym, state) → action

對XKB,setting 或 locking一個修飾鍵就是一個觸發動作,且這亦是任何X伺服器中互動 好比切換控制台、中斷伺服器、移動遊標等等。觸發動作通常不影響按鍵象徵,且產生按鍵象徵的不是觸發動作。

每個(按鍵象徵 keysym, 按鍵狀態 state)配對只有一個觸發動作。

編輯佈局設定 Editing the layout

從你的伺服器有的任何預設設定檔開始。 只要可以的話,產生一項小變動就馬上測試這變動。

xkbcomp 產生的 .xkb檔案為簡單文字檔。 C++風格註解, // 到一行終止可允許。段落名稱--好比在 xkb_keycodes 裡的 "name-here" --此處不重要且可以忽略。

xkb_keycodes

xkb的鍵碼(keycode)定義。其餘的檔案不使用數字型鍵碼,只有按鍵象徵按鍵標籤定義於這個段落。

他是好主意保留這些鍵碼定義。鍵盤有問題實際上在這裡。

這些按鍵標籤可以隨意定。 他們僅用在xkb_symbols 段落。

xkb_types

這一段放在xkb_symbols前面,所以先看看,不過先不要產生電動。標準類別依賴許多虛擬修飾鍵(virtual modifiers),這些將在後面解釋。現在,只要找到你需要的類別。從下列中開始:ONE_LEVEL、 TWO_LEVEL、 ALPHABETIC 。

ONE_LEVEL 這項值不被修飾鍵影響;通常他設給 Enter, Space, Escape, F keys, Shift/Alt/Ctrl 鍵等等。, TWO_LEVEL 與 ALPHABETIC 項值依據 Shift的狀態產生不同按鍵符號。所有字母數字鍵屬於這個類別。ALPHABETIC額外相關於CapsLock。

類別描述他們自己相當簡單。這行

   modifiers= Shift+NumLock+LevelThree;

意思是這些鍵被影響於 按鍵Shift, NumLock and LevelThree 位元而已。 映射(Map)行像

   map[Shift+LevelThree]= Level4;

定義哪個組合鍵對應哪個位階值。 程式xkbcomp複製預設值時使用"LevelN",但簡短又方便的"N"也可以用。

level_name那行不太影響且可以忽略。

xkb_compatibility

在所有設定之中 觸發動作定義(interpret)與鍵盤上led (indicator)。你可以移除資料你沒有的或用不到的,像附加數字鍵觸發、滑鼠控制或額外的修飾鍵。

注意這 key+AnyOfOrNone(all)key 等效,但key更容易給人讀懂。

看看群組切換(groups switching)如果有必要的話。如果有N個群組的話 LockGroup(group=N) 可以用,不然ISO_Next_Group/ISO_Prev_Group就夠了。LatchGroup 對非常規設定很有用。

xkb_symbols

主要的段落來定義那個按鍵做什麼。語法:

   key <LABL> { [ G1L1, G1L2, G1L3, ... ], [ G2L1, G2L2, G2L3, ... ], ... }

<LABL> 是按鍵標籤從 xkb_keycodes 段落來的,GiLj 群組i位階j的按鍵象徵。每個群組的按鍵象徵數目必須配合哪個類別的位階數目定義(xkbcomp 將警告你如果項目不存在)

查看 /usr/include/X11/keysymdef.h 可能的按鍵象徵清單。 撇開這些清單,你也可以用 Unnnn 給 Unicode 符號加上十六位元碼 nnnn, 例如: U0301 給組合符號 重音符號。 注意 aU0061 視為不同地 (目前, 多數應用程式期待 Ctrl+a, 不是 Ctrl+U0061 因為他們的數字值不一樣。)

按鍵類別也在這指定,其中像

   key.type = "T1";
   key <...> { ... };
   key <...> { ... };
   key <...> { ... };
   key.type = "T2";
   key <...> { ... };
   key <...> { ... };

或單獨設給每一個按鍵:

   key <...> { type = "T", [ .... ], [ .... ] };

按鍵類別可能在不同群組不一樣。這很反直覺,但實際上也有很方便的應用。要設定個別群組類別,用這個:

   key <...> { type[1] = "T1", type[2] = "T2", [ ... ], [ ... ] };

你可以設定標籤讓群組使用

   name[1] = "EN";     // group 1
   name[2] = "RU";     // group 2
   name[3] = "UA";     // group 3

如果標籤在這裡啓用,xxkb 將顯示他。 is what xxkb will show if labels are enabled there.

這一段落也包含 modifier_map 行。 目前先留著這行,或跳去看看後面的虛擬修飾鍵(Virtual Modifiers)。

xkb_geometry 鍵盤位置構造

完全不重要的章節描述鍵盤按鍵位置構造。可以刪除沒有任何後果。

基本範例 Basic examples

首先檢視你的現存規劃檔,他很可能包含給許多常見按鍵的標準定義。

通過這文字(text) -> "xkb_keycodes { text }" 表示 "text" 應該被加入 xkb_keycodes 段落裡。 無論何時,由上下文很清楚地,段落名稱被省略了。 (從.xkb檔可看到 xkb_keycodes "evdev+aliases(qwerty)" { blabla~ },引用檔案/usr/share/xkb/keycode/裡面的 檔案evdev 跟 檔案aliases 裡面段落qwerty 那一段內容)

簡易按鍵分配

啓用附加(又叫多媒體)按鍵:

   xkb_keycodes {
       <VOL-> = 122;       // 數值查看xev
       <VOL+> = 123;
   }
   xkb_symbols {
       key.type = "ONE_LEVEL";
       key <VOL-> { [ XF86AudioLowerVolume ] };
       key <VOL+> { [ XF86AudioRaiseVolume ] };
   }

Escape鍵設在 CapsLock鍵, 通常給 Vim 使用者:

   key.type = "ONE_LEVEL";
   key <CAPS> { [ Escape ] };

交換按鍵 Ins 跟 PrintScreen (有案例 他們彼此相反 — 發生在 Dell筆記電腦按鍵):

   key.type = "ONE_LEVEL";
   key <IN?>  { [    Print ] };
   key <PRSC> { [   Insert ] };

在某些 HP 筆記本電腦按鍵,上面那段作用。 相反地, the keycodes他們自己需要被定義:

   partial xkb_keycodes "insert" {
       alias <I118> = <IN?>;
       <INS>  = 218;
       <I218> = 118;
   };

改變按鍵 shift 到粘着按鍵(sticky key)版:

取代這行

   key <LFSH> {         [         Shift_L ] };

用這

   key <LFSH> {         [         ISO_Level2_Latch ] };

你應該也需要加入下面設定到/usr/share/X11/xkb/compat/basic

   interpret ISO_Level2_Latch+AnyOf(all) {
       useModMapMods=level1;
       action= LatchMods(modifiers=Shift,clearLocks,latchToLock);
   };
   interpret ISO_Level2_Latch+AnyOfOrNone(all) {
       action= LatchMods(modifiers=Shift,clearLocks,latchToLock);
   };

多重佈局 Multiple layouts

對一般字母數字按鍵,只要加入 第二/第三/第四個中括號 [ ] 段落到按鍵定義:

   key.type = "ALPHABETIC";
   key <AD01> { [ q, Q ], [ a, A ] };      // QWERTY佈局跟AZERTY(法式鍵盤佈局)
   key <AC02> { [        s,        S ],        // 多了兩個西里爾字母 cyrillic 的佈局
                [    U044B,    U042B ],
                [    U0456,    U0406 ] };

佈局切換藉着設定啟動 觸動動作(action) LockGroup 完成:

   interpret ISO_Next_Group { action = LockGroup(group=+1); };
   interpret ISO_Prev_Group { action = LockGroup(group=-1); };

通常這意味放置 ISO_Next_Group 與 ISO_Prev_Group 按鍵象徵在在恰當的 群組(group)/位階(level) 位置。 注意包括的群組,所以此設定如果你有兩個群組且敲兩次按鍵,你會回歸開始的群組。

西里爾字切換在兩個或以上的佈局以專用按鍵RWIN:

   key.type = "ONE_LEVEL";
   key <RWIN> { [ ISO_Next_Group ] }

如果你有更多佈局且某些按鍵要節約,可能最好有個專用鍵設給每個佈局。例如給三重佈局:

   key.type = "ONE_LEVEL";
   key <RCTL> { [ ISO_Next_Group ],    // g1: switch to g2
                [ ISO_Prev_Group ],    // g2: switch back to g1
                [ ISO_Prev_Group ] };  // g3: switch to g2
   key <MENU> { [ ISO_Prev_Group ],    // g1: switch to g3
                [ ISO_Next_Group ],    // g2: switch to g3
                [ ISO_Next_Group ] };  // g3: switch back to g1

有四個佈局,你將很可能得用觸發動作 ISO_First_Group 與 ISO_Last_Group。

同樣想法可以被實現以僅僅一個按鍵藉著用類型 TWO_LEVEL type:

   key.type = "TWO_LEVEL";
   key <MENU> { [ ISO_Next_Group, ISO_Prev_Group ],
                [ ISO_Prev_Group, ISO_Next_Group ],
                [ ISO_Prev_Group, ISO_Next_Group ] };

這方法的 Menu鍵 設給第二個群組 且 Shift-Menu鍵 設給第三個群組。要使用按鍵 Ctrl or Alt 而不是Shift,替代 TWO_LEVEL 用 PC_CONTROL_LEVEL2 或 PC_ALT_LEVEL2 對應的類別。

切換使用兩個修飾鍵(Shift+Shift, Ctrl+Shift 等等) 可藉由使用用某些不同於ONE_LEVEL類別給這些按鍵。 Shift+Shift 範例:

   key.type = "TWO_LEVEL";
   key <LFSH> { [ Shift_L, ISO_Prev_Group ] };
   key <RTSH> { [ Shift_R, ISO_Next_Group ] };

要鎖住一個群組(也就是切過去;設成只有你按哪個鍵那一次時), 使用 LatchGroup 觸發動作 一般綁定成 ISO_Group_Latch 按鍵象徵:

   key <RCTL> { [ ISO_Group_Latch ] }

調整 ISO_Group_Latch 在xkb_compatibility 那一章節的定義 以使用正確群組:

   interpret ISO_Group_Latch { action = LatchGroup(group=3); };

檢查 /usr/share/X11/xkb/symbols/group 有更多標準範例。

Caps + hjkl 作為 vim風格方向鍵

This article or section needs language, wiki syntax or style improvements. See Help:Style for reference.

Reason: The purpose of this section is not clear. (Discuss in Talk:X keyboard extension (正體中文))

如果目標鍵將用在鍵盤捷徑上 產生按鍵規劃時有明確的修飾鍵在按鍵按下中是最好的。例如,反白文字用基本鍵盤(Shift+Left)、或改變交談在多數即時通訊軟體 (Alt+Down) 將不會作用,如果有額外Caps修飾鍵送過去時。不過,額外的修飾鍵必須送出 如果使用者重新綁定一個字母鍵僅把按鍵象徵放在符號哪個段落。重新綁定也附帶許可功能就像 AHK(auto hot key)的blind command。

types 類別段落 (這行定義位階映射) 必須包含特定項目例如(此例 hjkl四個字母):
  • 當沒有修飾鍵按下,按下字母按鍵的第一位階的按鍵象徵被送出 (例如hjkl按鍵的小寫字母)。
  • 當單獨Shift鍵被按下,按下字母按鍵的第二位階的按鍵象徵被送出 (hjkl的大寫字母).
  • 單獨當鎖定鍵(Lock)被按下,按下字母按鍵的第三位階的按鍵象徵被送出 (此例hjkl對應的方向鍵)
  • 當 Shift 與 Lock 被按下,按下字母按鍵的第三位階的按鍵象徵被使用 (等同 此例 shift+方向鍵).

加入這個到你的類別段落最底部

 xkb_types "complete" {
   ...
   type "CUST_CAPSLOCK" {
       modifiers= Shift+Lock;
       map[Shift] = Level2;            //映射 shift鍵 且不含 Lock鍵。 Shift+Alt 也作用,因為 Alt 鍵不在上面那行修飾鍵中,。
       map[Lock] = Level3;
       map[Shift+Lock] = Level3;       //映射 shift and Lock鍵. Shift+Lock+Alt 也作用。
       level_name[Level1]= "Base";
       level_name[Level2]= "Shift";
       level_name[Level3]= "Lock";
   };
 };

現在來變更caps鍵設定從 lock (toggle)鍵動作去設定成 (press) 按住動作,藉着在兼容性那一章節所述來修改已經存在的定義 自 LockMods觸發動作 改成 SetMods動作:

(注意這修改意味你不能再像一般方式使用 capslock鍵)

 xkb_compatibility "complete" {
   ...
   interpret Caps_Lock+AnyOfOrNone(all) {
       action= SetMods(modifiers=Lock);
   };
   ...
 };

最後修改你的符號檔如下列。

 xkb_symbols "pc_us_inet(evdev)" {
   ...
   key <AC06> {
       type= "CUST_CAPSLOCK",
       symbols[Group1]= [               h,               H,               Left],
       actions[Group1]= [      NoAction(),      NoAction(),   RedirectKey(keycode=<LEFT>, clearmods=Lock) ]
  };

額外的象徵符號

同一按鍵可輸入更多種字。

構成鍵 Compose key

簡單設定且輸入一般Unicode字元很有用。

   key <RALT> { [ Multi_key ] };

位階3(Level3)

點子類似 Alt鍵 or AltGr鍵 以他們原本的意思: 字母數字按鍵得到額外字元,藉著按住某些修飾按鍵來用。

首先,設定修飾鍵。

   xkb_symbols {
       key <LWIN> { [ISO_Level3_Shift ] };
       modifier_map Mod5 { ISO_Level3_Shift };
   }

同樣,下面這些應該先在相對應段落被定義好,不過如果沒有的話就設定:

   xkb_compatibility {
       interpret ISO_Level3_Shift { action= SetMods(modifiers=Mod5); };
   }
   xkb_types {
       type "THREE_LEVEL" {
           modifiers= Shift+Mod5;
           map[Shift]= Level2;
           map[Mod5]= Level3;
           map[Shift+Mod5]= Level3;
           level_name[Level1]= "Base";
           level_name[Level2]= "Shift";
           level_name[Level3]= "Level3";
       };
       type "FOUR_LEVEL" {
           modifiers= Shift+LevelThree;
           map[Shift]= Level2;
           map[LevelThree]= Level3;
           map[Shift+LevelThree]= Level4;
           level_name[Level1]= "Base";
           level_name[Level2]= "Shift";
           level_name[Level3]= "Alt Base";
           level_name[Level4]= "Shift Alt";
       };
   }

註記下在xkb_compatibility 和 xkb_types 這段的標準定義有 LevelThree 而不是Mod5。不過只要上面的修飾鍵映射(modifier_map)使用Mod5,沒有實際差別,不管怎樣最後你將用Mod5位元。

現在,按鍵自定義群組,在這個案例的vi風格遊標動作:

   key.type = "THREE_LEVEL";
   key <AC06> { [ h, H,  Left ] };
   key <AC07> { [ j, J,  Down ] };
   key <AC08> { [ k, K,    Up ] };
   key <AC09> { [ l, L, Right ] };

如你可能用xev得知,這設定產生Mod5+Left鍵 而不僅僅是 Left鍵。 但那也可以的 在多數應用程式忽略他們用不到的狀態位元情況下。另一個解決方案,看看 覆蓋(Overlays)做法如下。

Meta, Super and Hyper 鍵

真正的修飾鍵 Real modifiers

某些應用程式 (特別是 emacs) 允許有意的使用更高位的狀態位元。他通常假定除了Shift, Ctrl 與 Alt 等這些按鍵控制位元之外, 還有修飾鍵叫做 Meta, Super 與 Hyper 存在鍵盤上。

從 XKB 觀點這意味設定 Mod2, Mod3, Mod4 and Mod5 修飾鍵位元。因為你所要的是按鍵自己的位元,沒有必要去編輯類別,就像之前 Level3 那個例子。

   xkb_compatibility {
       interpret Super_L { action = SetMods(modifiers=Mod3); };
   }
   xkb_symbols {
       key <LWIN> { [ Super_L ] };
       modifier_map Mod3 { Super_L };
   }

標準定義在 xkb_compatibility之中使用 Super修飾鍵而不是 Mod3 。你也可保持這樣,只要確定有modifier_map這行。

留心在 ModN 和已命名的 Super, Hyper 或甚至 Alt等修飾鍵 沒有嚴格對應關係。唯一廣泛使用的 Mod1;某些應用程式叫他 Meta,某些叫他 Alt。至於其他的,查查特定應用程式如何對待狀態位元,可看看下述 虛擬修飾鍵(Virtual modifiers)。

按鍵象徵追蹤 Keysym tracking

至少有一種應用程式(openbox) 已知追蹤這些 按鍵按下KeyPress/KeyRelease按鍵放開時的事件: Meta_[LR], Super_[LR] 和 Hyper_[LR] 等等按鍵象徵,取代依賴狀態值的位元。 在這情況下

   xkb_symbols {
       key <LWIN> { [ Super_L ] };
   }

已足夠且你可以省略用 interpretmodifier_map 行。

談到 Openbox,注意他確實允許兩種方法: "S-h" 追蹤 Super_[LR] 事件 而 "Mod3-h" 檢查相關的狀態位元。

預先設置檔 Preset configuration

XKB 通常藉著指定這幾項來設定:XkbTypes/XkbCompat/XkbSymbols, or XkbModel/XkbLayout (+XkbVariant/XkbOptions), or XkbKeymap;檔案位置一般在/etc/X11/xorg.conf or /etc/X11/xorg.conf.d/*.conf,像這樣:

   Option  "XkbModel"    "thinkpad60"
   Option  "XkbLayout"   "us,sk,de"
   Option  "XkbVariant"  "altgr-intl,qwerty,"
   Option  "XkbOptions"  "grp:menu_toggle,grp_led:caps"

這些值定義所有XKB映射(這個可以被xkbcomp轉存)。事實上,給xkbcomp的等效.xkb檔案可以來自 setxkbmap -print

   setxkbmap -model thinkpad60 -layout us,sk,de -variant altgr-intl,qwerty \
       -option -option grp:menu_toggle -option grp_led:caps -print

注意下上面的命令終端機輸出後 include 已經不一樣了。每一段落用的檔案從相對應的子目錄取得 在/usr/share/X11/xkb之中,也就是

   xkb_types { include "complete" };

代表 xkbcomp 將找 /usr/share/X11/xkb/types/complete。 plus符號表示並列相關,所以

   xkb_keycodes { include "evdev+aliases(qwerty)" };

代表

   xkb_keycodes {
       include "evdev";
       include "aliases(qwerty)";
   };

括號內可從檔案選已命名的段落。 查看 /usr/share/X11/xkb/keycodes/aliases 並注意

   xkb_keycodes "qwerty" { ... };

這是 aliases(qwerty) 部分參考處。 最後,冒號轉移佈局的一部份到另一個群組。

不像 XkbTypes/XkbCompat/XkbSymbols/XkbGeometry 的值,都直接地相關 .xkb 檔案的段落, XkbModel, XkbLayout and XkbRules 參考額外的 non-xkb 檔案 可在下面發現 /usr/share/X11/xkb/rules/ 這個配合 model 與 layout 值去指定符號(symbols) 和 鍵盤幾何構成(geometry)。 XkbKeymap 參考完整的按鍵規劃。參照 Ivan Pascal 記錄得到詳細敘述。

就好像用xkbcomp能達到的,這類設定可以馬上完成: 用指令 setxkbmap 不帶 -print 選項。

檔案 /usr/share/X11/xkb 是好範例來源,特別當他涉及標準鍵盤功能及非平常的XKB實現(例如 keypad/NumLock 處理)。同樣,在前階段時這些檔案你必須編輯以推動你的改變。看看 X Keyboard Config Rules 在編輯檔案之前。

xmodmap

儘管有時用在結合預先設置, xmodmap 不直接相關於XKB。 這個工具用不同想法 (pre-XKB) 於鍵盤代碼在X中如何被處理;特別是,xmodmap缺少群組與類別的概念,所以嘗試每按鍵超過一個以上按鍵象徵不太很可能工作。

通常不建議用 xmodmap,或許對很簡單工作是例外。 XKB-compatible 等效於 xmodmap 是 xkbcomp;然而, xkbcomp 缺少 -e 選項(執行表達式),所以不那麼易用。不管怎樣,不論何時應該寧願用 xkbcomp。

指示器 Indicators

如 "keyboard LEDs" 鍵盤那段落。 指示器命名被使用於搭配在 xkb_keycodes 段落中的實體數目LED。 除此此外,他們不相關。指示器不搭配在任何叫做"virtual"的LED;xkbvleds (package xorg-xkbutils) 可被用於檢查他們的狀態。 例子:

   xkb_keycodes {
       indicator 1 = "LED1";       // first physical LED
   }

指示器是總反映指定部分的 XKB 內部狀態。兩種通用模式被顯示於修飾鍵狀態:

   xkb_compatibility {
       indicator "LED1" { modifiers = Lock; }; // CapsLock indicator
   }

或目前群組:

   xkb_compatibility {
       indicator "LED1" { groups = 0x06; };    // "group 2 or group 3 is active"
   }

這個值是位元掩碼(bitmasks)。對於群組,位元1爲群組1,位元2爲群組2 後面如此序。

修飾鍵與類別 Modifiers and types

有時候有必要清除類別區段,也可引入非常用類別。

類別與修飾鍵緊密相關,所以很有意義地在做任何類別描述事情前從從修飾鍵開始。

決定要用那個位元,他們只有8個。且這些 Shift, Control and Mod1 已廣範用在應用程式中,並且 Lock (又叫 CapsLock鍵) 有預定義意思也可能難於覆蓋。然而其餘的4個可無礙運用。

警告: 四個標準類別, ONE_LEVEL, TWO_LEVEL, ALPHABETIC and KEYPAD, 接到特殊對待於 xkbcomp。 他們作用不同只因他們被以作用命名。如果某些修改不如預起作用,試著加入新類別代替。

使用實體修飾鍵在標準類別 Using real modifiers in standard types

取決於你的基本設定檔而定,可能有許多不常用標準類別像 EIGHT_LEVEL 或 PC_RCONTROL_LEVEL2。 移除他們以避免不需要的作用。

現在,某些類別使用虛擬修飾鍵。如果你決定用他們,檢查虛擬修飾鍵如下且略過這一段。 否則,有個好主意是去完全移除他們。檢查所需類別,且一是用相對應的實體鍵取代他們,或相關定義。範例。

   type "KEYPAD" {
       modifiers= Shift+NumLock;
       map[Shift]= Level2;
       map[NumLock]= Level2;
       level_name[Level1]= "Base";
       level_name[Level2]= "Number";
   };

如果你用 Mod2 用於 NumLock, 改類別成

   type "KEYPAD" {
       modifiers= Shift+Mod2;
       map[Shift]= Level2;
       map[Mod2]= Level2;
       level_name[Level1]= "Base";
       level_name[Level2]= "Number";
   };

如果你不再用 NumLock 修飾鍵, 改成

   type "KEYPAD" {
       modifiers= Shift;
       map[Shift]= Level2;
       level_name[Level1]= "Base";
       level_name[Level2]= "Number";
   };

作的雷同 xkb_compatibility 那段。 一旦修改完成,你應該能移除所有 "virtual_modifiers" 在檔案中這行。

切換單一修飾鍵位元

基本上你只需要按鍵象徵加上有關的解釋項(interpretation entry)。例如爲了用LWIN 切換 Mod5 ,用ISO_Level3_Shift設給按鍵象徵:

   xkb_compatibility {
       interpret ISO_Level3_Shift { action = SetMods(modifiers=Mod5); };
   }
   xkb_symbols {
       key <LWIN> { [ISO_Level3_Shift ] };
   }

撇開 SetMods, 你也可以用 LockModsLatchModsSetMods 產生通常的 "按住時持續 on while pressed" 修飾按鍵. LockMods 產生 "開/關 on/off" 如同 CapsLock 或 NumLock那樣切換。 LatchMods 表示 "開啟,直到下個按鍵按下 on until next keypress" 又稱粘性修飾鍵。

修飾鍵規劃 modifier_map

修飾鍵規劃是一張表單含有映射每個修飾鍵8位元值給至少4個按鍵:

   modifier_map Mod1 { Alt_L, Alt_R };

在核心協定,沒有 XKB, 這代表或多或少同樣的事

   interpret Alt_L { action = SetMods(modifiers=Mod1); };
   interpret Alt_R { action = SetMods(modifiers=Mod1); };

XKB不用修飾鍵規劃他原本的意思。在XKB中,他唯一作用是去用在規劃虛擬修飾鍵(參考下文)。

然而,這個修飾鍵規劃表單很容易給客戶端存取,且有一個反直覺(但常見)技巧在此: 修飾鍵規劃被用來告知哪個ModX位元是Alt。因為這樣,最好有個修飾鍵規劃爲如上文 Alt_L 或 Alt_R。除非你有好理由,否則最好設爲Mod1。

多鍵盤 Multiple keyboards

XKB 允許按鍵規劃給單一連接上的唯一實體鍵盤。 這個特徵極度有用於多鍵盤設定,當鍵盤是不一樣的;想想有個全尺寸USB鍵盤連接著。

首先,使用xinput (安裝包 xorg-xinput) 以獲得 device IDs:

   AT Translated Set 2 keyboard                id=11   [slave  keyboard (3)]

現在,

   xkbcomp -i 11 file.xkb $DISPLAY

   setxkbmap -device 11 ...

將設定按鍵規劃給指定id的鍵盤而已。頃印XKB設定動作也是:

   xkbcomp -i 11 $DISPLAY file.xkb

注意 xkbcomp -i11將不給出明確的任何錯誤訊息。確定你有空格在 -i後面。

除錯 XKB

當按鍵不照預想工作,第一件事要檢查XKB內部狀態:修飾鍵、影響的群組與控制位元。這三個都可以被用來驅動LED燈;使用xkbvleds去檢查他們

   indicator "LED1" { modifiers = Lock; };
   indicator "LED2" { groups = 2; };
   indicator "LED3" { controls = audiblebell; };

此外 xkbwatch 顯示所有 (真實的) 修飾鍵及他們 固定lock/暫閂住latch 狀態. 修飾鍵也被xev報告。 安裝包 Xxkb 可被用來監控影響的群組,但確定two_state模式已關閉。

在狀況解釋那段沒有作用良好,確定有檢查重複的 "interpret" 區塊。 最好,試著檢查相對應的特定按鍵象徵。查看段落9.2有解釋。

也產生個想法去檢查什麼是伺服器確實收到的,藉著下載按鍵規劃

   xkbcomp $DISPLAY out.xkb

輸出結果結果傾向不同於輸入檔案,。沒有已知地解決方法。

虛擬修飾鍵 Virtual Modifiers

XKB最讓人困擾的部分之一,虛擬修飾鍵出現於所有標準按鍵規劃檔,儘管儘管存在相對次要且大多無用特徵。這名詞本身非常有誤導性,且大多數文件沒有進一步幫助。

所以,首先: 虛擬修飾鍵不是所有實體修飾鍵之一。 如果有什麼意思,那就是個方法去命名某些實體修飾鍵。那不是有更多16位元而可以用於位階定義。那是16個可能名稱,每個參考到8個修飾鍵位元之1(有可能某些或沒有參照到)。

實體修飾鍵位元稱爲 Shift, Lock, Control 與 Mod1-Mod5。 Alt 不在其中。 虛擬修飾鍵被介紹爲允許表示某鍵例如

   #define Alt Mod1

給應用程式將使用這個訊息。

可以去定義一個有用鍵盤佈局沒有定義到任何虛擬修飾鍵;在標準修飾鍵中,僅有 Alt/Meta 實際需要如此對待,因為無論如何 Shift 和 Control 是實體修飾鍵且 NumLock 不常用於修飾鍵。

同樣,不像大多數按鍵規劃相關的、影響應用程式使用基本的Xlib功能的事物,虛擬修飾鍵必須被質疑明確使用。不是所有應用程式實際這麼做。

定義虛擬修飾鍵 Defining virtual modifiers

在虛擬修飾鍵與實體修飾鍵之間是個定義,以有點奇怪地方式使用按鍵象徵,如同一個媒介。因為某些理由在此之後參考XKBproto 。真實修飾鍵叫做 M 被分配給一個鍵用:

   modifier_map M { <keysym> };

虛擬修飾鍵 V 可以被分配給一個鍵用:

   interpret <keysym> { virtualMod = V; };

如果一個虛擬修飾鍵 V 共享於至少一個按鍵象徵給真實修飾鍵 M ,那就是被綁定給 M 鍵。

注意虛擬修飾鍵命名不在預定義中 且 必須得使用前宣告於 xkb_compatibility 與 xkb_types 段落:

   xkb_compatibility "complete" {
       virtual_modifiers LevelThree,NumLock,Alt;
   }

按鍵象徵解釋 Keysym interpretation

虛擬修飾鍵可被用 interpret <keysym> 區塊如同他們被定義於相對應的實體修飾鍵。對一個虛擬修飾鍵 V 不綁定於任何實體修飾鍵,這代表

   #define V

類別宣告且

   interpret <key> { }
   interpret <key>+V { }

此區塊將被視爲重複。在檔案中僅有他們之中最後一項將作用。像這種例子xkbcomp通常會給警告。

客戶端側註記 Client side notes

處理 XKB 虛擬修飾鍵在客戶端側需要某些非瑣碎伺服器解譯。大多數應用程式只是不操心,附上8個真實修飾鍵提供在 XKeyEvent.state。

不過,那是有可能給應用程式獲得虛擬修飾鍵結合按鍵按下。 Gtk,例如, gdk-keymap-translate-keyboard-state()[失效連結 2024-07-30 ⓘ] 那個功能可能有也可能沒有被用於特定應用程式。

某些人可能實現某些事像虛擬修飾鍵支援,但實際沒有。檢查Openbox在章節5.3.3.2。關於Alt處理,查看章節 8.3。(備註:搜尋不到openbox的文件,待高手補充)

XKB 控制位元

一堆位元標誌影響不同方面的XKB功能性。要控制他們, 用 {Set,Latch,Lock} 控制觸發動作。

滑鼠控制 Mouse control

XKB允許控從鍵盤制滑鼠指標。 檔設定適當,他極度有用。 然而,他的可用性依賴許多特定實體鍵盤的佈局規劃跟使用者喜好上。

從XKB 觀點看這相對簡單來實現,修改人只要觸發相關動作。 相當完全的實現可被發現於 /usr/share/X11/xkb/compat/mousekeys

注意那觸發動作將不會工作除非 MouseKeys 控制位元有設定:

   interpret Pointer_EnableKeys { action= LockControls(controls=MouseKeys); };

由於大多數鍵盤沒有專用滑鼠控制鍵, 結合 MouseKeysOverlay 其中之一的標記可能是好主意。

   interpret Pointer_EnableKeys { action= LockControls(controls=MouseKeys+Overlay1); };

這設定允許滑鼠遊標控制鍵到適當覆蓋區塊:

   xkb_keycodes {
       <MUP> = 218;
       <MDWN> = 212;
       <MLFT> = 214;
       <MRHT> = 216;
   }
   xkb_symbols {
       key   <UP> { [    Up ], overlay1 = <MUP> };
       key <LEFT> { [  Left ], overlay1 = <MLFT> };
       key <RGHT> { [ Right ], overlay1 = <MRHT> };
       key <DOWN> { [  Down ], overlay1 = <MDWN> };
       key <MUP>  { [ Pointer_Up ] };
       key <MDWN> { [ Pointer_Down ] };
       key <MLFT> { [ Pointer_Left ] };
       key <MRHT> { [ Pointer_Right ] };
   }

這方法他可能去分配 non-mouse 觸發動作到按鍵來用於控制滑鼠, 且因此, 給個例子, 使用修飾按鍵去產生滑鼠按鈕事件。

Local XKB folder

你可以設定一個 X 來自本機檔案的按鍵規劃,用下列命令:

$ xkbcomp keymap.xkb $DISPLAY

這裡 keymap.xkb 必須有個結構,像

keymap.xkb
xkb_keymap {
    xkb_keycodes  { ... };
    xkb_types     { ... };
    xkb_compat    { ... };
    xkb_symbols   { ... };

    // 下行的鍵盤按鍵位置構造項目完全是選擇性使用。
    // xkb_geometry  { include "pc(pc104)" };
};

你可以用 includes 從這個檔案, 這裡 the inclusion 參考自本機資料夾而不是 /usr/share/X11/xkb。 爲了這個你需要用 -I/path/ 參數。例如:

$ xkbcomp -I$HOME/.xkb $HOME/.keymap.xkb $DISPLAY
$HOME/.keymap.xkb
xkb_keymap {
    xkb_keycodes  { include "evdev+aliases(qwerty)" };
    xkb_types     { include "complete" };
    xkb_compat    { include "complete" };
    xkb_symbols   { include "pc+custom+inet(evdev)" };
};

符號檔必須有同樣命名如同上面例子 xkb_symbols的那行。 The symbol file must have the same name as specified in the xkb_symbols right above.

$HOME/.xkb/symbols/custom
partial alphanumeric_keys xkb_symbols "custom" { ... };

問題排除

有個usb鍵盤 當插拔之後設定消失了 I have an USB keyboard and the settings get lost upon unplugging it

使用 rules 替代靜態按鍵規劃設定會讓你更有彈性和長久性按鍵規劃映射那不需手動地(或用腳本script) Using rules instead of static keymap configuration will give you a more flexible and permanent key mapping that does not need to be reloaded manually (or by a script).

也參考 See also