【Xmodmap】Linuxのキーボード配列を自分でカスタマイズする方法

# はじめに
Linuxのキーボード配列（キーボードレイアウト）を自分好みに変える方法を記載しております。
Xmodmapを使ってレイアウト変更を行っていきます。

# 環境
以下の環境にて実施しました。
Debian系統のOSであれば特に問題ないかと。

* OS：　Linux Mint 22.1 Cinnamon
* ハードウェア：　レッツノート（CF-LX4）

# 参考文献

[xmodmap](https://wiki.archlinux.jp/index.php/Xmodmap)
[XMODMAP](http://xjman.dsl.gr.jp/man/man1/xmodmap.1x.html)
[キーバインドの変更 Xmodmapの基本的な設定方法](https://qiita.com/macinjoke/items/746c0c0adb74cfdeb9e7)
[xmodmapを使った Ubuntu18.04でのキーバインド変更](https://qiita.com/syabonbubble/items/873754f8902b52751ee5)

[X keyboard extension](https://wiki.archlinux.jp/index.php/X_keyboard_extension)
[XKBの設定ファイルを直接編集してキーボードレイアウトをカスタマイズする](https://qiita.com/ZeptByteS/items/db1de2cbd940c65b8d1f)

# 現在のキーコード一覧を表示する
現在のキーボードに何が割り当てられているか？
これを確認するには以下のコマンドを実行します。

```bash:現在のキーコードを一覧出力させる
xmodmap -pke
```

実行すると、現在割り当てられているキーコードがいっぱい出てきます。
あまりにも多いので、一部抜粋で載せます。

```bash:キーコード一覧（一部抜粋）
（略）

keycode  22 = BackSpace BackSpace BackSpace BackSpace NoSymbol NoSymbol Terminate_Server
keycode  23 = Tab ISO_Left_Tab Tab ISO_Left_Tab
keycode  24 = q Q q Q
keycode  25 = w W w W
keycode  26 = e E e E
keycode  27 = r R r R
keycode  28 = t T t T
keycode  29 = y Y y Y
keycode  30 = u U u U
keycode  31 = i I i I
keycode  32 = o O o O
keycode  33 = p P p P
keycode  34 = at grave at grave
keycode  35 = bracketleft braceleft bracketleft braceleft
keycode  36 = Return NoSymbol Return
keycode  37 = Control_L NoSymbol Control_L
keycode  38 = a A a A
keycode  39 = s S s S
keycode  40 = d D d D

（略）
```

ざっくりとした読み方は以下の通り。

```bash:読み方の説明
keycode [キーコード値] = [キー] [左Shift+キー] [キー] [右Shift+キー]

[左Shift+キー]：左Shiftを押しながら
[右Shift+キー]：右Shiftを押しながら
[キー]２つ目：これは分かりませんでした
```

キーコードを変更した際、このキーコード一覧表も変更した値で表示されます。
ちゃんと変更できたか確認する際にも使用できますね。

# キーを押してキーコードを表示する
一覧表では正直ゴチャついていて見にくいと思います。

実は、ピンポイントでキーコードを取得することもできます。
以下のコマンドを実行し、取得したいキーを押せば、キーコードが表示されます。

```bash:キーを押してキーコードを出力させる
xev | grep keycode
```

試しに「G」を押して見ましょう。
こんな感じになります。

​    state 0x0, keycode <font color="red">42 </font>(keysym 0x67, g), same_screen YES,
​    state 0x0, keycode <font color="red">42</font> (keysym 0x67, g), same_screen YES,

赤字が押したキーのキーコードです。

# キーボード配列のカスタマイズ
ここから具体的にキーボードの配列を変更する手順になります。
ここでは以下を題材にして説明していきます。

> 題材
> [CapsLock] に [左Ctrl] を割り当てる

## [手順1] 設定ファイル ~/.Xmodmap の作成
まず初めに、ホームディレクトリに `~/.Xmodmap` ファイルがあるか確認します。
ファイルが無ければ以下のコマンドで作ります。

```bash:~/.Xmodmapを作成する
touch ~/.Xmodmap
```

この `~/.Xmodmap` に、変更したいキーボード配列を記述していきます。
例えば、以下のことができます。

* [CapsLock] を [Ctrl] に変更
* [変換] を [Alt] に変更
* [カタカナひらがな｜ローマ字] を [スタート] に変更

など。

## [手順2] 修飾キーに割り当てられているキーコードを確認する
修飾キーとは「CtrlやShiftのように、他のキーの機能を一時的に切り替えるキー」のことです。
具体的には、

* Shiftキーで、大文字を打てるようになる
* Ctrlキーで、取り消し・貼り付けなどができる
* Altキーを押しながらTabキーを押して、アクティブウィンドウを切り替えれる

といったように、普段使っているキーに、別の役割を引き立たせるキーです。

では、修飾キーを表示していきます。
以下のコマンドを実行すると、現在の修飾キーに割り当てられているキーコードが表示されます。

```bash:修飾キーを出力させる
xmodmap
```

実行すると、以下のような出力が得られるかと思います。

```bash:修飾キーの一覧
xmodmap:  up to 4 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Eisu_toggle (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Alt_R (0x6c),  Alt_L (0xcc),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3        ISO_Level5_Shift (0xcb)
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c)
```

今回は「CapsLockに左Ctrlを割り当て」たいので、

* lock        Eisu_toggle (0x42)　　（★）
* control     Control_L (0x25),  Control_R (0x69)

の項目を見返せるようにメモしておきます。

:::note info
**（★）について**

`lock` がCapsLock機能を意味します。
もしかしたら、この`lock`の表示が、

lock        Caps_Lock (0x42)

となっている方もいるかもしれません。
これは「Fcitx」という日本語入力を対応させるソフトが関係しているかと思われます。
（申し訳ないですが、確信はありません。憶測です。）

出力内容が異なると不安になってしまうことをもありますが、
特段問題なく、`lock` の項目は、出力された内容で進めてください。

* Caps_Lock (0x42)　（10進数：　66）
* Eisu_toggle (0x42)　（10進数：　66）

この記事では、後者の「Eisu_toggle (0x42)」で説明していきますが、
コメントに「Caps_Lock (0x42)」と明示していきます。

ちなみに、`control` はそのままCtrl機能のことで、

* Control_L (0x25)：　左のCtrlキー（Escキー側）
* Control_R (0x69):　右のCtrlキー（Enterキー側）

ということです。
:::

## [手順3] ~/.Xmodmapにキーコード割り当ての処理を記述する
何らかのテキストエディタを使って `~/.Xmodmap` を開きます。
ここではvimを使っています。

```bash:~/.Xmodmapを開く
vim ~/.Xmodmap
```

[CapsLock] に [左Ctrl]を割り当てる処理を記載していきます。
CapsLockとCtrlのキーコードは [手順2] でメモをとった内容になります。

* Eisu_toggle (0x42) または Caps_Lock (0x42)　（▲10進数：　66）
* Control_L (0x25)
* Control_R (0x69)

:::note info
**（▲）について**

割り当てられるキー（CapsLock (0x42)）には、10進数に変換したキーコード（66）が必要です。

では、Control_L/R は10進数にしなくても良いのか？
これは、しなくても良いです。

CapsLockは別のキーで割り当て「られる」ので、自身のキーコードは必要になります。
しかし、Control_Lは自身のキーコードを別のキーに割り当て「る」ので必要はありません。

CapsLock (0x42) <-- (キーコード割り当て) -- Control_L (0x25)
　　↓
CapsLock (0x25)

ただ、Control_Lを別のキーに割り当てたいのであれば、
Control_L自身のキーコードが必要になります。

例えば、Control_LをEnterにカスタマイズする場合であれば、
Control_L自身のキーコードは、Enterのキーコードで割り当て「られる」必要がありますからね。
:::

記述する処理は以下の通り。

```sh:~/.Xmodmap
! CapsLockに左Ctrlを割り当てる

! 一旦、割り当てられているキーコードを削除
clear lock
clear control

! 「CapsLock」に「左Ctrl」を割り当て（10進数で書く）
keycode 66 = Control_L    ! CapsLockのキーコードは「66（10進数）」
add control = Control_L Control_R    ! controlを削除したので、再び左Ctrlと右Ctrlを割り当てて元に戻す
```

いきなり見せつけられても何だか分からないので、
簡単に説明します。

### clear：初期化する
後述しますが `add` 命令でキーコードを割り当てても、
上書きされるだけで、初期値は残ったままになります。

そこで `clear` 命令を使います。
`clear` 命令は、割り当てられているキーコードをすべて削除します。

こんな感じのイメージです。

```bash:~/.Xmodmap
! clearする前
! lock        ：Eisu_toggle (0x42)
! control     ：Control_L (0x25),  Control_R (0x69)

! clearを実行する
clear lock
clear control

! clearした後
! lock        ：（空）
! control     ：（空）
```

### keycode：キーコードを割り当てる
`keycode` で、指定したキーを、別のキーに割り当てることができます。

キーコードの基本フォーマットは以下のとおりです。

```bash:keycodeの基本フォーマット
keycode [割り当て「られる」キーのキーコード (10進数)] = [割り当て「る」キーのキーコード (文字列)]
```
CapsLockを左Ctrlで割り当てるので、
基本フォーマットには、

* [割り当て「られる」キーのキーコード (10進数)]：　66（CapsLockのキーコード）
* [割り当て「る」キーのキーコード (文字列)]：　Control_L

を当てはめます。

```sh:~/.Xmodmap
keycode 66 = Control_L    ! CapsLockのキーコードは「66（10進数）」
```

### add：キーコードを上書きで割り当てる
`add` 命令は1つのキーに、複数のキーコードを割り当てることができます。
`add` 命令は、

```bash:~/.Xmodmap
key          ! key == （空）
add key = a  ! key == a
add key = b  ! key == a b
```

のように、後ろにキーコードを追加して割り当てます。
スタックのようなイメージですね。

## [手順4] 設定を反映させる
`~/.Xmodmap` の記述が完了したので、
実際にキーボードに反映していきます。

### バックアップ
その前に、何かあったときのために、元に戻せるようにしておきます。
以下のコマンドを実行して、バックアップファイル `.Xmodmap_bk` に残しておきます。

```bash
xmodmap -pke > ~/.Xmodmap_bk
```

ファイル名は何でもOKです。

### xmodmapコマンドで反映する
xmodmapコマンドの引数に、`~/.Xmodmap` ファイルを指定して実行すると、
その内容が反映されます。

```bash:~/.Xmodmapの反映
xmodmap ~/.Xmodmap
```

実行した後、CapsLockがCtrlに変わります。

以上で、キーボード配列のカスタマイズは完了になります。

## [おまけ] 永続的に反映させる
実は、xmodmapでキーボード配列を設定しても、
ずっとは設定を維持してくれません。

* ログアウトをすると元に戻る　（残念ながら・・・）
* 電源をOFFにすると元に戻る

こんなことになってしまいます。

ですが、電源をOFFにしても設定を維持する方法があります。
その方法を説明していきます。

> ログアウトに関しては、設定を維持する方法が分かりませんでした。
> `~/.bash_profile` や `~/.profile` に 
> 　　　`xmodmap ~/.Xmodmap`
> を記述しても、処理は動いています（リダイレクトで確認）が、
> 設定は反映されませんでした。

まず `~/.xkbmap` が存在するか確認してください。
存在しなければ、以下のコマンドで作成します。

```bash:コマンドライン
touch ~/.xkbmap
```

次に、`~/.Xmodmap` ファイルを反映させます。

```bash:コマンドライン
xmodmap ~/.Xmodmap
```

現在のxmodmapをxkbファイルに変換します。

```bash:コマンドライン
xkbcomp $DISPLAY $HOME/.xkbmap
```

最後に、

```bash:コマンドライン
xkbcomp /home/user/.xkbmap $DISPLAY
```

これで、電源をOFFにして、またONにしてもキーボード配列は維持されます。

# サンプル一覧

## 「CapsLock」を「左Ctrl」に変更
題材と同じです。
CapsLockを左Ctrlに変えてみます。

* 割り当てられるキー：　CapsLock
* 割り当てるキー：　左Ctrl

> こんな感じです。
> [CapsLock] → [左Ctrl]
> [左Ctrl] → [左Ctrl]（ここはそのまま）

```sh:~/.Xmodmap
! CapsLockに左Ctrlを割り当てる

! 一旦、割り当てられているキーコードを削除
clear lock
clear control

! 「CapsLock」に「左Ctrl」を割り当て（10進数で書く）
keycode 66 = Control_L    ! CapsLockのキーコードは「66（10進数）」
add control = Control_L Control_R    ! controlを削除したので、再び左Ctrlと右Ctrlを割り当てて元に戻す
```

後は、以下のコマンドで反映します。

```bash:~/.Xmodmapの反映
xmodmap ~/.Xmodmap
```

## 「変換」を「右Alt」に変更
[変換] キーを [右Alt] キーに変更します。

* 割り当てられるキー：　[変換]
* 割り当てるキー：　[右Alt]

[変換] キーと [右Alt] キーのキーコードを取得します。

まずは、以下のコマンドを実行して、
キーボードが押されたらキーコードを表示するようにします。

```bash
xev | grep keycode
```

次に、[変換] キーと [右Alt] キーを押して、
キーコードをメモしておきます。

state 0x0, keycode <font color="red">100</font> (keysym 0xff23, Henkan_Mode), same_screen YES,
state 0x0, keycode 64 (keysym 0xffe9, <font color="red">Alt_L</font>), same_screen YES,

[右Alt] キーが無ければ、 [左Alt] キーを押して、
Alt\_<font color="red">L</font> を Alt\_R<font color="red">R</font> に変えればOKです。

```:.Xmodmap
! [変換]に[右Alt]を割り当てる
keycode 100 = Alt_R    ! 「変換(100)」に「右Alt」を割り当て
```

後は、以下のコマンドで反映します。

```bash:~/.Xmodmapの反映
xmodmap ~/.Xmodmap
```

## 「カタカナひらがな｜ローマ字」を「右スタート」に変更
[カタカナひらがな｜ローマ字] キーを [右ウィンドウズ] キーに変更します。
[右スタート] とは [右ウィンドウズ] のイメージです。

* 割り当てられるキー：　[カタカナひらがな｜ローマ字]
* 割り当てるキー：　[右スタート]

[カタカナひらがな｜ローマ字] キーと [右スタート] キーのキーコードを取得します。

まずは、以下のコマンドを実行して、
キーボードが押されたらキーコードを表示するようにします。

```bash
xev | grep keycode
```

[カタカナひらがな｜ローマ字] キーと [右スタート] キーを押して、
キーコードをメモしておきます。

state 0x0, keycode <font color="red">101</font> (keysym 0xff27, Hiragana_Katakana), same_screen YES,
state 0x40, keycode 133 (keysym 0xffeb, <font color="red">Super_L</font>), same_screen YES,


[右スタート] キーが無ければ、 [左スタート] キーを押して、
Super\_<font color="red">L</font> を Super\_<font color="red">R</font> に変えればOKです。


```:.Xmodmap
! [カタカナひらがな｜ローマ字]に[右ウィンドウズ]を割り当てる
keycode 101 = Super_R
```

後は、以下のコマンドで反映します。

```bash:~/.Xmodmapの反映
xmodmap ~/.Xmodmap
```

## 「＼（バックスラッシュ）」と「＿（アンダーバー）」を入れ替える
Shiftを押さずに [＿（アンダーバー）] が出て、
逆にShiftを押しながらだと [＼（バックスラッシュ）] が出るように入れ替えます。

[＿（アンダーバー）] キーと [＼（バックスラッシュ）] キーのキーコードを取得します。

まずは、以下のコマンドを実行して、
キーボードが押されたらキーコードを表示するようにします。

```bash
xev | grep keycode
```

[＿（アンダーバー）] キーと [＼（バックスラッシュ）] キーを押して、
キーコードをメモしておきます。

state 0x0, keycode 97 (keysym 0x5c, <font color="red">backslash</font>), same_screen YES,
state 0x1, keycode 97 (keysym 0x5f, <font color="red">underscore</font>), same_screen YES,

```:.Xmodmap
! [＼（バックスラッシュ）]と[＿（アンダーバー）]を入れ替える
keycode 97 = underscore backslash
```

後は、以下のコマンドで反映します。

```bash:~/.Xmodmapの反映
xmodmap ~/.Xmodmap
```

## サンプルプログラムまとめ
今までのキー割り当てのまとめです。
やっていることは以下の通り。

* [CapsLock]に[左Ctrl]を割り当て
* [変換]に[右Alt]を割り当て
* [カタカナひらがな｜ローマ字]に[右スタート（ウィンドウズ）]を割り当て
* [＼（バックスラッシュ）]と[＿（アンダーバー）]を入れ替える
    * Shiftを押さずに[＿（アンダーバー）]が入力され、Shiftを押すと[＼（バックスラッシュ）]が入力されるようにする

```.Xmodmap
! [CapsLock]に[左Ctrl]を割り当てる
clear lock
clear control
keycode 66 = Control_L
add control = Control_L Control_R

! [変換]に[右Alt]を割り当てる
keycode 100 = Alt_R

! [カタカナひらがな｜ローマ字]に[右ウィンドウズ]を割り当てる
keycode 101 = Super_R

! [＼（バックスラッシュ）]と[＿（アンダーバー）]を入れ替える
keycode 97 = underscore backslash
```