XKBの設定ファイルを直接編集してキーボードレイアウトをカスタマイズする

##はじめに
この記事は、検索した情報と設定ファイルをいじくりまわした結果から自分なりの解釈を述べたものであり、記事内の説明や表現は正しくない可能性があります。

環境:
OS: Ubuntu 14.04LTS
Keyboard: Microsoft Natural Ergonomic Keyboard 4000 (US配列)
##準備
Ubuntu14.04LTSでは、xkbの設定ファイルは/usr/share/X11/xkb/以下にあります。

まずxkb/以下のフォルダを適当にコピーするなどしてバックアップしておきます。

その後適当なディレクトリから以下のコマンドを実行します。
このコマンドは、現在使用中の設定をひとまとめにしたkeymapファイルをdefault.xkbの名前でカレントディレクトリに作成します。
`$ xkbcomp $DISPLAY default.xkb`

さらに次のコマンドを実行します。
このコマンドはカレントディレクトリにあるdefault.xkbを読み込み、一時的にレイアウトを変更します。一度日本語入力にするなどレイアウトを切り替えると元に戻ります。 また、読み込んだファイルにエラーがある場合は、このコマンドの実行時にxkbcompが教えてくれます。
`$ xkbcomp default.xkb $DISPLAY`

このターミナルは開いたままにしておきます。
編集で失敗した際、カーソルキーの上とリターンさえ生き残っていれば、編集前の設定に一時的に戻せます。

次にテキストエディタなどで設定ファイルを編集します。

編集が終わったら/var/lib/xkb/以下にあるXKBのキャッシュを削除します。

```
$ cd /var/lib/xkb/
$ ls
server-11E5978A89165D56F1B4A2145DB8D0A1B3FE4475.xkm  server-2D6959D464E1825D6D6E5D463E0A218AD6D6F230.xkm  server-D378AD8F86E560F712A83EE36E4E5E92C595B9BD.xkm
server-26D181DC00C47208C01881402EB863FD09581C13.xkm  server-B20D7FC79C7F597315E3E501AEF10E0D866E8E92.xkm  server-E523AD9EC2D3CDDA418A43E9EA1EBB2909110507.xkm
$ sudo rm *.xkm

```

削除後、一度日本語入力にするなどレイアウトを切り替えると、編集した内容が反映され、新しいキャッシュファイルが生成されます。 生成されない場合は、編集した場所のどこかに文法エラーがある可能性があります。

編集する度に毎回再起動する必要はありません。設定ファイルにエラーがある状態で再起動すると、GUIでログインできなくなります。


##設定ファイルの種類とおおまかな役割

####compat

- 特定のシンボルに対しアクションを追加する
- 特定のインジケータを点灯させる条件を決める

####geometry

- Keyboard Layout Chartで表示されるキーボードのイメージを単純なコードで描いたファイル
- XKBから直接使われることはなく、見た目が気に入らない限り特に編集する必要はない

####keycodes
- keycode と keyname （`<AE12>`などの部分、keylabelなどとも呼ばれる）を対応づける
- 使用するインジケータの順番を決める


####rules

- どのファイルを使用するかを決めるためのルールがまとめられている
- 各ルールはセクションの先頭に [ ! パターン = 使用するファイルの種類 ] の形でパターンを指定し、以降ルールが書き並べられている 

####symbols

- keynameごとに使うsymbol, type, action, groupを定義する

####types
- どの修飾キーの組み合わせがどのShift-Levelになるかをコントロールする


詳細な解説
[X KeyBoard extension - ArchWiki -](https://wiki.archlinuxjp.org/index.php/X_KeyBoard_extension) 一部日本語

より詳細な解説
[Ivan Pascal (Homepage)](http://pascal.tsu.ru/en/xkb/) ぜんぶ英語
[Ivan Pascal (Homepage)](http://pascal.tsu.ru/other/xkb/) ぜんぶロシア語 (英語版のページだとリンクがないページも見れる)

##キー配置を変更する
###symbolsファイルの読み込まれる順番

symbolsファイルは左から順に読み込まれます。

```
$ setxkbmap -print
xkb_keymap {
	xkb_keycodes  { include "evdev+aliases(qwerty)"	};
	xkb_types     { include "complete"	};
	xkb_compat    { include "complete"	};
	xkb_symbols   { include "pc+us(dvorak)+us:2+inet(evdev)"	};
	xkb_geometry  { include "pc(pc104)"	};
};
```

この場合symbols/以下から、 pc, Group1としてus(dvorak), Group2としてus(basic), inet(evdev)の順に読み込まれていることを意味します。

```text:イメージ
pc+us(dvorak)+us:2+inet(evdev) == pc + [Group1] = us(dvorak) + inet(evdev)
                                       [Group2] = us(basic)
                                       [Group3] = Empty
                                       [Group4] = Empty
```

ほとんどの場合選択したレイアウト以外にpcとinet(evdev)が読み込まれますが、特殊なキーボードモデルやレイアウトを使っている場合は、xkb/rules以下のルールによって別のファイルが読み込まれます。

us(dvorak)は、symbols/usファイル内のdvorakセクションという意味です。

us(basic):2ではなくus:2のようにファイル内のセクションが指定されていない場合は、そのファイル内でdefault指定されているセクションを意味します。

```cpp:xkb/symbols/us
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		]	};
    ...
```


後から読み込まれたファイル内で同じキーが定義されていた場合、**変更部分のみ**が上書きされます。

例えば、バックスペース\<BKSP\>について、次のように定義されているとします。

```cpp:pc
key <BKSP> {	[ BackSpace, BackSpace	]	};
```

```cpp:us(dvorak)
key <BKSP> {	[ Delete ]	};
```

```cpp:inet(evdev)
key <BKSP> {
        type[group1]="FOUR_LEVEL",
        symbols[Group1]= [ NoSymbol,                NoSymbol,   comma,      less ],
        actions[Group1]= [ RedirectKey(key=<I162>), NoAction(), NoAction(), NoAction() ]
    };
```

`NoSymbol`は、シンボルがないことを意味します。
`NoAction()`はアクションがないことを意味します。

この場合、最終的に読み込まれる設定ファイルでは、key \<BKSP\>は次のようになります。

```cpp
key <BKSP> {
        type[group1]="FOUR_LEVEL",
        symbols[Group1]= [ Delete,                  BackSpace,  comma,      less ],
        actions[Group1]= [ RedirectKey(key=<I162>), NoAction(), NoAction(), NoAction() ]
    };
```
###編集するファイル
![symbols_pc.png](https://qiita-image-store.s3.amazonaws.com/0/67844/7b71c610-7a1e-0edf-ff57-8282e196d498.png)

- 上の図で緑色のキー: symbols/pcを編集する
- 音量や画面の明るさ調整などのメディアキー: symbols/inet(evdev)を編集する
- それ以外のキー: symbols/us もしくは使用するレイアウトファイルを編集する

`key <BKSP> {    [ Delete        ]   };`
キー配置を変更するには、各キーのシンボルを入れ替えます。
左側の`key <BKSP>`の部分は物理的なキーの位置だと思ってください。
右側の [ ] の中がこのキーを押した時に使われるシンボル(keysym)です。
[ ] の中には修飾キーの状態によって8種類までのkeysymを指定できます。 これはShift-Levelと呼ばれ、Shift-Levelはxkb/types/以下のファイルによってコントロールされます。
明示的にtypeを指定しない場合、自動的にXKBがShift-Levelの数やkeysymの種類によってTWO_LEVEL, ALPHABETIC, FOUR_LEVELなどを割り当ててくれます。


```cpp:pc
default  partial alphanumeric_keys modifier_keys
xkb_symbols "pc105" {
//    Shift-Level     Level1     Level2
//    key <BKSP> {	[ BackSpace, BackSpace	]	};
    key <BKSP> {	[ Delete       	]	}; // BackSpaceをDeleteにする

//    key <RTRN> {	[ Return		]	};
    key <RTRN> {	[ Control_R		]	}; // ReturnをControl_Rにする

//    key <CAPS> {	[ Caps_Lock		]	};
    key <CAPS> {	[ Control_L		]	}; // Caps_LockをControl_Lにする

//    key <LCTL> {	[ Control_L		]	};
    key <LCTL> {	[ Caps_Lock		]	}; // Control_LをCaps_Lockにする


// symbols/altwin(meta_alt)をincludeせずにAlt_LにBackSpaceを、Alt_RにReturnを割り当てる
//    include "altwin(meta_alt)" 
    key <LALT> {        [ BackSpace ] };
    key <RALT> {        [ Return ] };
    modifier_map Mod1   { Alt_L, Alt_R }; // real modifier [ Mod1 ] をAlt_L, Alt_Rに割り当てる

//    key  <INS> {	[  Insert		]	};
//    key <HOME> {	[  Home			]	};
//    key <PGUP> {	[  Prior		]	};
//    key <DELE> {	[  Delete		]	};
//    key  <END> {	[  End			]	};
//    key <PGDN> {	[  Next			]	};

//  Pageup, Pagedown, Home, Endの位置をカーソルキー風に変更する
    key  <INS> {	[ ]	};
    key <HOME> {	[  Prior		]	};
    key <PGUP> {	[ ]	};
    key <DELE> {	[  Home 		]	};
    key  <END> {	[  Next			]	};
    key <PGDN> {	[  End			]	};
};

```

デフォルトではsymbols/altwin(meta_alt)をincludeしており、\<LALT\>,\<RALT\>のLevel2にMetaが割り当てられるので、この行をコメントアウトしてpc内で左右のAltキーをカスタマイズしています。


他のkeysymは`/usr/include/X11/keysymdef.h`で確認できます。

```cpp:/usr/include/X11/keysymdef.h
/* Modifiers */
// "XK_"の部分を取り除いた文字列を使う
#define XK_Shift_L                       0xffe1  /* Left shift */
#define XK_Shift_R                       0xffe2  /* Right shift */
#define XK_Control_L                     0xffe3  /* Left control */
#define XK_Control_R                     0xffe4  /* Right control */
#define XK_Caps_Lock                     0xffe5  /* Caps lock */
#define XK_Shift_Lock                    0xffe6  /* Shift lock */
```

### real modifier, virtual modifier
virtual modifierはXKB内でのみ使われ、任意の名前でreal modifierよりも多く作成可能です。 real modifierは実際にプログラムに伝えられる値で、Control、Shift、Lock（Caps Lock）、Mod1〜Mod5の8種類があります。 real modifierを新たに作成したり名前を変更することはできません。

virtual modifierはプログラムへ伝えられる前に`modifier_map Mod1   { Alt_L, Alt_R };`のようにいずれかのreal modifierに結びつける必要があります。

XKBはこのvirtual modifierごとに違った機能を割り当て、結びつけられたreal modifierは同じでも、別の機能を持った修飾キーとして識別して使うことができます。

デフォルトではMod1がAlt、 Mod2がNum Lock、 Mod4がSuper、 Mod5がLevel3ShiftやMode_switchなどに割り当てられています。 Mod3は未使用のようです。

### 使用するメディアキーを symbols/pc で管理する
inet(evdev)に用意されているメディアキーのうち、実際に使われるのは一部です。 使用中のキーボードがどのメディアキーを使っているかを調べ、inet(evdev)内で該当するキーをコメントアウトし、pc内にコピーしておくと、後からカスタマイズしたくなった時に楽かもしれません。

### 現在使用中のメディアキーを調べる

コマンド`$ xev | sed -n 's/^.*keycode *\([0-9]\+\) (keysym .*, \(.*\)),.*$/keycode \1 = \2/p'`を実行し、すべてのメディアキーを押していく

```text
$ xev | sed -n 's/^.*keycode *\([0-9]\+\) (keysym .*, \(.*\)),.*$/keycode \1 = \2/p'
...
keycode 36 = Return
keycode 180 = XF86HomePage
keycode 180 = XF86HomePage
keycode 225 = XF86Search
keycode 163 = XF86Mail
keycode 163 = XF86Mail
keycode 192 = XF86Launch5
...
```
`XF86HomePage`などのシンボル名でinet(evdev)内を検索する
`key <I180>   {      [ XF86HomePage          ]       };`

特定のキーを押しても反応がない場合は、そもそもスキャンコードが送信されていないか、マッピングされたキーコードが通常XKBで扱える8-255の範囲外に設定されている可能性があります。

[特別なキーボードキー - ArchWiki - ](https://wiki.archlinuxjp.org/index.php/%E7%89%B9%E5%88%A5%E3%81%AA%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%82%AD%E3%83%BC)

スキャンコードやらキーコードやら色々ありますが、登場するコードはこんなかんじです。

```text:イメージ
KEY_PAGEUP                  |        XKB設定ファイル
                            |
scancode    keycode(evtest) |  keycode(xev)     keyname     keysym
7004b       104             |  112         =    <PGUP>     [ Prior ]
                            |
```

###Microsoft Natural Ergonomic Keyboard 4000 (US配列)の場合
このキーボードでは、ズームスライダーとSpell Check(Function Lock offの時のF10キー)を認識してくれず、 xevコマンドを実行してからこれらのキーを入力しても、なにも表示されません。 

[Make the zoom slider of Microsoft Natural Ergonomic Keyboard 4000 and 7000 scroll up and down, in 14.04 (Trusty) - Ask Ubuntu -](http://askubuntu.com/questions/471802/make-the-zoom-slider-of-microsoft-natural-ergonomic-keyboard-4000-and-7000-scrol)

まず、evtestコマンドを実行してこれらのキーを押して情報を確認します。(evtestのインストールが必要です)

```
$ sudo evtest /dev/input/event13
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x45e product 0xdb version 0x111
Input device name: "Microsoft Natural® Ergonomic Keyboard 4000"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 1 (KEY_ESC)
    Event code 2 (KEY_1)
    ...
    Event code 610 (?)
    Event code 611 (?)
    Event code 612 (?)
    Event code 613 (?)
  Event type 2 (EV_REL)
    Event code 6 (REL_HWHEEL)
  Event type 3 (EV_ABS)
    Event code 32 (ABS_VOLUME)
      Value      0
      Min        0
      Max     1023
  Event type 4 (EV_MSC)
    Event code 4 (MSC_SCAN)
Properties:
  Property type 20 (EV_REP)
    Property code 0 (REP_DELAY)
      Value    250
    Property code 1 (REP_PERIOD)
      Value     33
Testing ... (interrupt to exit)
Event: time 1461479765.860282, type 4 (EV_MSC), code 4 (MSC_SCAN), value c01ab
Event: time 1461479765.860282, type 1 (EV_KEY), code 432 (KEY_SPELLCHECK), value 1
Event: time 1461479765.860282, -------------- SYN_REPORT ------------
Event: time 1461479765.964286, type 4 (EV_MSC), code 4 (MSC_SCAN), value c01ab
Event: time 1461479765.964286, type 1 (EV_KEY), code 432 (KEY_SPELLCHECK), value 0
Event: time 1461479765.964286, -------------- SYN_REPORT ------------
Event: time 1461479767.653197, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022d
Event: time 1461479767.653197, type 1 (EV_KEY), code 418 (KEY_ZOOMIN), value 1
Event: time 1461479767.653197, -------------- SYN_REPORT ------------
Event: time 1461479767.773259, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022d
Event: time 1461479767.773259, type 1 (EV_KEY), code 418 (KEY_ZOOMIN), value 0
Event: time 1461479767.773259, -------------- SYN_REPORT ------------
Event: time 1461479768.925768, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022e
Event: time 1461479768.925768, type 1 (EV_KEY), code 419 (KEY_ZOOMOUT), value 1
Event: time 1461479768.925768, -------------- SYN_REPORT ------------
Event: time 1461479769.013793, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022e
Event: time 1461479769.013793, type 1 (EV_KEY), code 419 (KEY_ZOOMOUT), value 0
Event: time 1461479769.013793, -------------- SYN_REPORT ------------
```
上記のコマンドを実行して対象のキーを押しても反応がない場合は、`$ sudo evtest /dev/input/event12`など、指定するeventの値を変えて実行してみてください。 このキーボードの場合、スキャンコードが送信されないFunction Lockは押しても反応がなく、カスタマイズすることはできません。

この場合、必要な情報は各キーの`(MSC_SCAN), value c01ab`の部分の値です。

`etc/udev/hwdb.d/61-keyboard-local.hwdb`を新しく作成し、さきほど取得した値の先頭に0をつけ、新しく割り当てるキーを指定します。

```sh:61-keyboard-local.hwdb
keyboard:usb:v045Ep00DB* # Microsoft Natural Ergonomic Keyboard 4000
 KEYBOARD_KEY_0c022d=move # zoomin
 KEYBOARD_KEY_0c022e=edit # zoomout
 KEYBOARD_KEY_0c01ab=iso # spell_check

# KEYBOARD_KEY_0c022d=pageup # zoominをPageUpとして使う場合(key <PGUP>のシンボルを使う)
```

ズームスライダーはPageUp/Downとして使われることが多いようですが、カスタマイズしやすいようにsymbols/inet(evdev)にてデフォルトでコメントアウトされている以下のキーに割り当て、symbols/pcに追加しておきます。

```cpp:pcに追加
key <I183>   { [ Prior ] }; // KEY_MOVE
key <I184>   { [ Next ]  }; // KEY_EDIT
key <I178>   { [ XF86Spell ] }; // KEY_ISO
```

```cpp:inet(evdev)
// key <I183>   {      [ ]       }; // KEY_MOVE
// key <I184>   {      [ ]       }; // KEY_EDIT
// key <I178>   {      [ ]       }; // KEY_ISO
```

コメントに記載されている名前から、KEY_を取り除いて小文字にしたものを61-keyboard-local.hwdbで使用します。

その他の選択肢は`usr/include/linux/input.h`で確認することができます。

保存した後、`$ sudo udevadm hwdb --update`を実行し、再起動すると、ズームスライダーとSpell Checkが機能するようになります。



##特殊なシンボルを入力できるようにする
例として、English(Dvorak)でLevel3_Shiftと Y を押して ¥、 € を入力できるようにします。

```cpp:symbols/us
partial alphanumeric_keys
xkb_symbols "dvorak" {
    ...
    name[Group1]= "English (Dvorak)";
    key <AD03> { [      period,	greater, dead_abovedot, periodcentered	] };
    key <AD04> { [	    p,	P		]	};
    key <AD05> { [	    y,	Y, yen, EuroSign]	};// keysymに ¥ と € を追加
```

```cpp:symbols/pc
default  partial alphanumeric_keys modifier_keys
xkb_symbols "pc105" {
    ...
    // include "altwin(meta_alt)"// symbols/altwin(meta_alt)をincludeしない
    key <LALT> {        [ Alt_L ] };
    key <RALT> {        [ ISO_Level3_Shift ] };// <RALT>をLevel3_Shiftとして使う
    modifier_map Mod1   { Alt_L };
```

Level3 + Y で ¥、 Level3 + Shift + Y で € が入力できます。 
##新しいレイアウトを作成する
English(Dvorak, no dead keys)を作成してみます。
追加したレイアウトを使用するには再起動が必要です。
まずsymbols/usを編集します。

1. symbols/us内のdvorakセクションをコピーし、Programmer Dvorakの後に貼り付ける
2. グループ名とセクション名（バリアント名）を変更する
3. include "us(dvorak)"を追加する
4. Level4まであるキー以外を削除する
5. 行の先頭に replace をつけ、Level3, Level4のシンボルを削除する

```cpp
xkb_symbols "dvp" {...
};

partial alphanumeric_keys modifier_keys // symbols/pcの内容を上書きする場合はmodifier_keysなどを追加する
xkb_symbols "dvorak-simplified" {
    include "us(dvorak)"

    name[Group1]= "English (Dvorak, no dead keys)";
    // replaceを追加したキーには、includeしたus(dvorak)の内容は含まれず、新しい内容で置き換えられる
    replace key <TLDE> { [        grave,  asciitilde ] };
    replace key <AE06> { [            6, asciicircum ] };
    replace key <AE09> { [            9,   parenleft ] };
    replace key <AE12> { [ bracketright,  braceright ] };
    replace key <AD01> { [   apostrophe,    quotedbl ] };
    replace key <AD02> { [        comma,        less ] };
    replace key <AD03> { [       period,     greater ] };
    replace key <AB01> { [    semicolon,       colon ] };

    key <RTRN> {	[ Control_R		]	}; // ReturnをControl_Rにする
    key <CAPS> {	[ Control_L		]	}; // Caps_LockをControl_Lにする
    key <LCTL> {	[ Caps_Lock		]	}; // Control_LをCaps_Lockにする
    key <RCTL> {    [ Return        ]   }; // Control_RをReturnにする
};
```
作成したus(dvorak-simplified)セクションにsymbols/pcにあるキーを追加すると、カスタマイズした内容はこのレイアウトを選択している時のみ有効になります。

次に作成したEnglish (Dvorak, no dead keys)のルールをxkb/rules以下の4つのファイルに追加します。

- base.lst
- base.xml
- evdev.lst
- evdev.xml
 
```cpp:base.lst,evdev.lst
! variant
  chr             us: Cherokee
  euro            us: English (US, with euro on 5)
  intl            us: English (US, international with dead keys)
  alt-intl        us: English (US, alternative international)
  colemak         us: English (Colemak)
  dvorak          us: English (Dvorak)
  dvorak-intl     us: English (Dvorak, international with dead keys)
  dvorak-alt-intl us: English (Dvorak alternative international no dead keys)
  dvorak-l        us: English (left handed Dvorak)
  dvorak-r        us: English (right handed Dvorak)
  dvorak-classic  us: English (classic Dvorak)
  dvp             us: English (programmer Dvorak)
  dvorak-simplified us: English (Dvorak, no dead keys) // この行を追加
```

```xml:base.xml,evdev.xml
<variant>
          <configItem>
            <name>dvorak-classic</name>
            <description>English (classic Dvorak)</description>
          </configItem>
        </variant>
        <variant>
          <configItem>
            <name>dvp</name>
            <description>English (programmer Dvorak)</description>
          </configItem>
        </variant>
        <variant><!--ここから-->
          <configItem>
            <name>dvorak-simplified</name>
            <description>English (Dvorak, no dead keys)</description>
          </configItem>
        </variant><!--ここまでを追加-->
```

キャッシュを削除してから再起動すると新しいレイアウトが選択できるようになります。
![Dvorak_no_dead_keys.png](https://qiita-image-store.s3.amazonaws.com/0/67844/0abf1751-ec88-891f-1390-27721311c3d5.png)


##グループを使用する
グループは、ひとつのレイアウト内で複数のレイアウトを使用できる仕組みです。
例えば、普段はDvorakとMozcを使っていて、たまにQwertyが必要になる時があるが、毎回English(Dvorak)-English(US)-Mozcと切り替えて使うのはめんどくさい、といった場合に役に立つかもしれません。

Dvorakなど、symbols/us内のEnglish(US)以外のレイアウトを使用すると、どういうわけか問答無用でグループ2にEnglish(US)が読み込まれます。その場合はキーボードのどこかにグループスイッチを追加するだけでOKです。

`key <RCTL> { [ ISO_Next_Group ] };`

その他の選択肢はxkb/compat/iso9995で確認することができます。

```cpp:iso9995
    ...
    interpret ISO_Group_Latch {
	useModMapMods= level1;
	virtualModifier= AltGr;
	action= LatchGroup(group=2);
    };

    interpret ISO_Next_Group {
	useModMapMods= level1;
	virtualModifier= AltGr;
	action= LockGroup(group=+1);
    };

    interpret ISO_Prev_Group {
	useModMapMods= level1;
	virtualModifier= AltGr;
	action= LockGroup(group=-1);
    };
    interpret ISO_First_Group {
	action= LockGroup(group=1);
    };

    interpret ISO_Last_Group {
	action= LockGroup(group=2);
    };
    ...
```
interpret に続いてシンボルの名前とアクションの内容が定義されています。ここでアクションの内容を編集して違う機能を持ったキーとして使うこともできます。

一度に使用できるアクションはひとつだけです。 例えば特定のキーを押すとグループをスイッチし、さらに修飾キーとしてControlを追加する、といったような使い方はできません。 複数のアクションが定義されていた場合は、エラーとなるか最後に読み込まれたアクションのみが適用されます。

[Actions description - Ivan Pascal (Homepage) - ](http://pascal.tsu.ru/en/xkb/gram-action.html)
[Compatibility Maps - An Unreliable Guide to XKB Configuration - ](http://www.charvolant.org/~doug/xkb/html/node5.html#SECTION00055000000000000000)

グループはひとつのレイアウトで4つまで使用できます。新しいグループを作成するには、任意のグループ名とkeysymを追加します。

```cpp
partial alphanumeric_keys
xkb_symbols "dvorak" {

    name[Group1]= "English (Dvorak)";
    name[Group3]= "Arrow keys"; // Group2は自動的にEnglish(US)となるので、Group3を使う

    key <AD02> { [ comma, less, dead_cedilla, dead_caron ],[],[Up] };
    ...
    //            Group1    Group2    Group3
    key <AC01> { [ a, A ], [      ], [ Left ] };
    key <AC02> { [ o, O ], [      ], [ Down ] };
    key <AC03> { [ e, E ], [      ], [ Right] };
    ...

```

##ホームポジションにカーソルキーを割り当てる
Group3を使ってHHKB風に特定のキーをスイッチにしてホームポジションのいくつかのキーをカーソルキーとして使えるようにします。
この方法ではグローバルホットキー以外ならショートカットキーもちきんと動作します。

![HHKB_Style.png](https://qiita-image-store.s3.amazonaws.com/0/67844/c6af18e1-8d43-f224-1508-b5a40100c2de.png)

```cpp:symbols/pc
default  partial alphanumeric_keys modifier_keys
xkb_symbols "pc105" {
    name[Group3]= "Arrow keys"; // Group3に名前をつける
    ...
    key <RCTL> { [ ISO_Last_Group ], [ ISO_Next_Group ] };
    ...
    //           [          Group1           ]  [ Group2 ]  [ Group3 ]
    key <AD08> { [ NoSymbol, NoSymbol,  Home ], [        ], [   Home ] };
    key <AD09> { [ NoSymbol, NoSymbol,   End ], [        ], [    End ] };
    key <AD10> { [ NoSymbol, NoSymbol,    Up ], [        ], [     Up ] };
    key <AC08> { [ NoSymbol, NoSymbol, Prior ], [        ], [  Prior ] };
    key <AC09> { [ NoSymbol, NoSymbol,  Left ], [        ], [   Left ] };
    key <AC10> { [ NoSymbol, NoSymbol, Right ], [        ], [  Right ] };
    key <AB08> { [ NoSymbol, NoSymbol,  Next ], [        ], [   Next ] };
    key <AB09> { [ NoSymbol, NoSymbol,  Down ], [        ], [   Down ] };
    ...
```

各キーのGroup1にある3つめのシンボルは、Keyboard Layout ChartでLast_Groupを押した時の機能を確認するためだけに存在し、実際に使われることはありません。 

Group2のQwertyレイアウトに切り替えた時もカーソルキーが使えるようにGroup2にもスイッチとなるキーを追加してあります。

```cpp:compat/iso9995
    ...
    interpret ISO_Next_Group {
    // useModMapMods= level1;
    // virtualModifier= AltGr;
    // action= LockGroup(group=+1);
    action= SetGroup(group=2);
    };

    interpret ISO_Last_Group {
    // action= LockGroup(group=2);
    action= SetGroup(group=3);
    };
    ...
```

###ISO_が先頭にあるシンボル
これらのシンボルは必要な時以外はプログラムに伝えられません。 
これはつまり、グローバルホットキー以外の大抵のプログラムでは、Control + ISO_Next_Group + s はControl + sとして扱われるということだと私は認識しています。

グローバルホットキーは少し仕組みが違うようで、例えばControl + ISO_Next_Group + sを入力しようとしてもsを入力する前にControl + ISO_Next_Groupとして認識されてしまいます。


##リマップしたキーがリピートしない場合
XKBの設定ファイルを使う場合symbolsファイルに`repeat=yes;`を追加する方法などがあるようですが、期待通りに動作しないので、~/.bashrcにxsetコマンドを追加するほうが簡単です。

```sh:~/.bashrc
#xset [-r [keycode]] [r [keycode]]
xset r  108 # <RALT>のリピートをオンにする
xset -r 36  # <RTRN>のリピートをオフにする
```
##参照
- [X KeyBoard extension - ArchWiki -](https://wiki.archlinuxjp.org/index.php/X_KeyBoard_extension)
- [An Unreliable Guide to XKB Configuration](http://www.charvolant.org/~doug/xkb/html/xkb.html)
- [Ivan Pascal (Homepage) 英語](http://pascal.tsu.ru/en/xkb/)
- [Ivan Pascal (Homepage) ロシア語](http://pascal.tsu.ru/other/xkb/)
- [特別なキーボードキー - ArchWiki - ](https://wiki.archlinuxjp.org/index.php/%E7%89%B9%E5%88%A5%E3%81%AA%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%82%AD%E3%83%BC)
- [Make the zoom slider of Microsoft Natural Ergonomic Keyboard 4000 and 7000 scroll up and down, in 14.04 (Trusty) - Ask Ubuntu -](http://askubuntu.com/questions/471802/make-the-zoom-slider-of-microsoft-natural-ergonomic-keyboard-4000-and-7000-scrol)