4月の半ばに入ってから、父のお下がりのPC(ややこしいですが、こちらのPCを以降、新しいPCと呼ぶことにします。お下がりではありますが、僕にとっては新しく手に入れたPCなので)を手に入れました。
今まで持っていたマシンはすべてWindowsだったので、普段はMSYS2を利用して、Linuxっぽい環境を使っていました。しかし、一度は本物のLinuxも使ってみたいところです。
一応、Windows上でWSL2を使えば本物のLinuxを動かせはしますが、僕の持っているマシンは積んでいるメモリが少なすぎて、WSL2を起動するのが不安でした(そのせいで、WSL2はほとんど使ってきませんでした)。
そこで、新しいPCはLinux機として活用させてもらうことにしました。Linux”っぽい”環境は3-4年くらい使っていたのですが、本物のLinuxを使うのは初めてだったので、よく初心者向けにおすすめされているUbuntuを入れました。
ということで、これからは本物のLinux上でbashスクリプトを実行したり、Windowsには無いコマンド操作でファイルを弄りたおせるぞと、とてもワクワクしながら使い始めました。
特にWindowsでは、Linux(MSYS2)のfindコマンドを使おうとすると、コマンドの絶対パスを指定する必要があって、なかなかに不便でした(絶対パスを指定せずにfind
と入力しただけだと、Windows標準のfindコマンドが使われてしまうからです)。
一応エイリアスを利用して、絶対パスをfindで参照できるようにしていたのですが、それでは解決できませんでした。なので、結局は毎回findの絶対パスを入力していました。
findコマンドも含めて、様々なコマンド操作は速くて便利なので、個人的にはWindows環境であってもよく使います。なので、何もしなくてもWindows標準のコマンドとの競合が発生しないというのは、とてもありがたいです。
ところが、そんなワクワクの矢先、Ubuntuを使っていると、少し気になることが出てきました。それは、Windowsを使っているときに慣れ親しんだキーマップが、いくつか違っていることです。
もしも何の手立ても無いのであれば、「OSが違うのだから仕方ないね」と諦めるのですが、どうやらそういうわけでもなさそうです。ということで、キーマップを変更しました。ところが、それが僕にはなかなか厄介で、滅茶苦茶躓きました。
ということで、キーマップの変更方法の備忘録(兼、誰かの役にも立てばいいな)的な記事を書いていきます。
ただし先述したとおり、僕はUbuntuを含め、本物のLinuxを使うのはほぼ初めてで、Ubuntuを使い始めてから2-3週間くらいしか経っていない時点でこの記事を書いています。なので、間違っていることや、間違ってはいなくても、あまり推奨されないことなども多々あると思います。ですから、この記事の内容を鵜呑みにはしないでください。
気になったことと、最終目標
僕の環境は次の通りです。
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.2 LTS"
以降はこの環境を前提として、話を進めていきます。
CapsLockを最終的にはこうしたい
この環境をインストールした後、何も設定していない状態で、僕が最も気になったのは、CapsLockの動作です。CapsLockだけを押したら、大文字入力・小文字入力の切り替えと同時に、全角と半角の切り替えも行うようになっていました。
僕の場合、そのような入力モード切り替えを利用することはありません。
しかし、大文字固定モードと小文字固定モードを切り替えることはよくあります。例えば、C++コード中の定数は大文字と(僕は)決めているので、大文字しか入力しないことが多々あります。そういったとき、常時大文字を入力するモードと常時小文字を入力するモードを切り替えられると、とても便利です。
この大文字と小文字モードを切り替えるという動作は、デフォルトのShift+CapsLockと同じ動作です。そのため、CapsLock単体で入力したときの動作をShift+CapsLockに変更してしまうのは勿体ない気がします。
というのも、CapsLockはとても便利な位置にあるので、せっかくならもう少し機能を持たせたいからです。
他によく使う動作としては、全角と半角の切り替えがあります。半角/全角キーを使えば全角と半角を切り替えられますが、ホームポジションから遠くて、僕はよく押し間違いをします。正確に押そうとすると、目線を手元に移さなければならないので、それも面倒です。
なので、CapsLock単体では全角と半角を切り替えられるように、キーマップを変更することにします。
以上をまとめると、最終的に実現したいキーマップは次のようになります。
- CapsLock単体なら、全角・半角を切り替える(大文字・小文字モードの変更は行わない)
- Shift+CapsLockなら、大文字・小文字モードを切り替える(全角・半角は切り替えない)
つまり、Shiftキーを押しているかどうかによって、大文字・小文字切り替えとして使うのか、全角・半角切り替えとして使うのかを変更したいと。言い換えると、Shiftを押していないときは、全角/半角キーと同じ動作となって、Shiftを押しているときは、普通のCapsLockと同じ動作になってほしいということになります(こう表現した方が分かりやすかったかもしれませんね)。
gnome-system-monitorを起動できるようにしたい
他にも気になったこととして、Windowsで言うところのタスクマネージャーを簡単に開けないというものがあります。というのも、僕はたまにメモリ使用量が気になることがあるからです。なので、簡単にメモリ使用量を確認できるようにしたいなと思いました。
調べてみると、Windowsで言うところのタスクマネージャーは、Linuxならgnome-system-monitorになるようです。ただしgnome-system-monitorは、先頭にgnomeと付いているので、もしかしたらGNOMEを採用しているLinuxだけなのかもしれません。
Windowsなら、Ctrl+Shift+Escを押してタスクマネージャーを開けば、メモリ使用量を確認できるようになっています。
なので、gnome-system-monitorをCtrl+Shift+Escで開けるようにしたいです(結論から言えば、これはできなかったので、Ctrl+Shift+Mで開けるようにしました)。
以上のようなキー操作を実現するために、前提を確認したり、試行錯誤の過程を書いていきます。「そんなもん興味ねぇよ」と結論だけを知りたい方は、「xremapによるキーマップ変更」の節まで飛ばしてください。
Ubuntuの仕組みから見る、ダメな例
「それではさっそく設定を変更していこう」と話を進めたいところですが、まずはLinuxのことを知らなければいけません(必ずしもLinuxに詳しくなければいけないということもないのでしょうが、僕の場合はLinuxの仕組みを理解できていないために色々と失敗をしたので、ここでは先にざっくりと解説しておきます)。
今回話題としているLinuxですが、この「Linux」という単語は少々厄介で、OSを指すこともあれば、カーネルのことを指すこともあるらしいのです。
OSとカーネルがどう違うかと言えば、OSとは、例えばWindowsなどのように、コンピュータシステムをユーザーが使うときに必要なソフトウェアのことを指します。しかし、WindowsのようなOSは、カーネルと呼ばれるもっと基本的な機能を提供しているソフトウェアに依存しています。
つまり、まずカーネルというソフトウェアがあって、そのカーネルが提供している機能を利用してOSが作られているということですな。
これだけではまだイメージが難しいでしょうから、もう少し(皆さんに馴染みが無いであろう)カーネルを説明してみます。
例えば、Aというアプリがメモリを0番地から100番地までを使っていたとします。そして、次にBというアプリが起動されたとします。すると、Bもやはり動作のためにはメモリを使う必要がありますから、広大なメモリの中から、特に自分が使いたい場所を確保する必要があるわけです。
では、Bというアプリは勝手にメモリを利用できる(値を変更したり、値を参照したりできる)かと言えば、そういうわけではありません。というのも、0番地から100番地まではすでに使われていて、そこは避けなければならないからです。
もし仮にBというアプリが[0, 100]番地を利用してしまうと、Aというアプリに不正な値を入力することになってしまいます。もしも[80, 90]番地にパスワードが格納されていて、Bというアプリが、メモリの内容をすべて出力するというアプリだったとすると、Bを利用すれば、パスワードを見ることができてしまいます。
これがマズいということは、なんとなくご理解いただけるのではないでしょうか。そのコンピュータを一人しか使わないのであれば問題は起きにくいでしょうが、複数人が使うのなら、自分のパスワードが他者に知られるかもしれないからです。
※これと似たような現象を利用して、意図したバグを引き起こす動画が面白かったのでご紹介します。特に、同動画7:57からの”「本来マップとして使用されていないメモリ」の数値を参照している”という部分は印象的です。これに似たようなことがPCでも引き起こせてしまうと大きな問題となるのは想像に難くないでしょう。
※続. 僕は初代ポケモンのバグ技についてはあまり詳しくないので、もしかしたら間違っているかもしれません。「バッファオーバーランを利用して云々」といった説明を、たしか同じ方の別の動画で視たような気がします。なので、実際にはここでの説明とは似ていないのかもしれませんが、メモリの不正アクセスという観点では同じなので、ここで紹介しています。メモリに不正アクセスするとどうなるかというイメージが分からない方の参考になれば幸いです。
※続. ちなみに、まったく別のゲームを作るなんていう離れ業をやってのけた方もいらっしゃいます。
そのようなことが起きないように、カーネルというPCを動かしているコアのプログラムが、「あのアプリがここからここまでのメモリを使っているから、他のアプリが利用できるメモリはここからここまでだな」と、メモリの使用領域を管理している必要があります。そうしておけば、アプリ側に脆弱性があったとしても、他のアプリへの影響を抑えられるからです。
こういったことを、カーネルが僕たちに意識させないで行ってくれているわけです。もちろん、WindowsにもWindowsカーネルというものがあって、同じような仕事をこなしてくれています。ありがたや。
しかし、当然ながらユーザーに提供する機能はそれだけではまだまだ不十分です。他にファイルをHDDやSSDに書き込んだり、WiFi通信モジュールからの信号を読み取ったりと、様々な機能が必要です。
それらができて初めて、他の様々なソフトウェアが成り立っています。CUIで使われるコマンドもそうですし、GUIアプリもそうです。
しかし、Linuxカーネルは先ほど説明したような基本的な機能しか提供していません。なので、Linuxカーネルを利用したソフトウェアや、さらにそのソフトウェアを利用したソフトウェアとして、(CUIアプリかGUIアプリかに限らず)様々な種類が出てきても(原理上)おかしくありません。実際にそうなっています。
つまり、LinuxカーネルはLinuxと呼ばれるすべてのOSで共通しているけど、そのLinuxカーネルを利用するソフトウェアには様々なバリエーションがあると。
今回のテーマであるキー入力は、ディスプレイサーバーと呼ばれるソフトウェアに関係しているそうです。そして、そのディスプレイサーバーは、UbuntuではX Windows System(以下では、単にXと呼ぶことにします)とWaylandの2種類があるそうです。
Ubuntu22.04LTS以前はデフォルトでX Windows Systemを利用していたそうですが、22.04LTSからのデフォルトはWaylandに変更したそうな。
そして、ディスプレイサーバーによって使える設定方法、使えない設定方法が変わってくるそうです。要するに、キー入力はディスプレイサーバーに依存していると。
しかし、Linuxを触り始めた2-3週間前の僕は、そのことをよく理解できていませんでした。
Xで設定を変えようとして失敗
Xでは、xmodmapやxkbといったコマンドでキーマップを変更できると、ネットを検索していたら分かりました。
それで、色々と設定を書いていたのですが、僕の環境ではどうしても変更できませんでした。なぜか、jpキーボードを指定しているはずなのに、usキーボードが設定されてしまって、半角/全角を押すとバッククォーテーションが入力されて困ったこともありました。
もしかしたら僕の書いた設定ファイルに問題があったのかもしれません。
1週間弱、色々と格闘したり検索したりしているうちに、どうやらUbuntu22.04ではWaylandがデフォルトで使用されるようになっていて、Xを利用しているxmodmapやxkbは、キーマップの変更に利用できなさそうだということが分かりました。
※キーマップの設定が終わった時点で、いくつもファイルがあるとややこしいということで、設定をすべて削除してしまいました。なので、失敗例をお見せすることはできませんが、どれも結局は上手くいきませんでした。
しかし、使うディスプレイサーバーをWaylandからXに変更すれば、xmodmapやxkbを利用できそうです。ですが、次の節でお話しする理由から、僕はデフォルトのWaylandを使い続けることにしました。
Waylandを使っていきたい。
Waylandというディスプレイサーバーですが、最近は高dpiのディスプレイ(解像度の高いディスプレイということらしいです)が出てきたことで、ディスプレイサーバーはそれらへも対応できる必要が出てきたそうです。
そして、どのような仕組みでそうなっているのかは分かりませんが、XよりもWaylandの方が解像度を自由に変更しやすいという記事も、どこかで見かけました。そのため、XよりもWaylandの方が環境に適しているそうです。
環境に合ったものはこれから発展していくだろうと思ったので、ディスプレイサーバーをXには変更しないことにしました(つまり、Waylandを使う)。
Waylandを使うとなれば、前節でお伝えしたとおり、xmodmapやxkbは利用できませんから、代替手段が必要です。その代替手段としてxremapというOSSを利用することにしました。xremapはWayland環境でもキーマップを変更できるそうです。
※xmodmapは書き方が分かりづらかった上に資料が少なかったですし、xkbは古いらしいですから、これらを使わなくて済むのはありがたいです。
xremapによるキーマップ変更
今までは、前提の確認や僕の考え方を説明してきました。そして最終的に、xremapを利用することにしたことも説明しました。
結論から言えば、xremapによるキーマップ変更はそれなりに上手く行きました。今は次のような設定で動かしています。
# A workaround for the Wayland bug: https://github.com/k0kubun/xremap/issues/179
keypress_delay_ms: 20
#
keymap:
- name: Global
exact_match: true
remap:
CapsLock: Grave
C-Shift-Esc:
launch: ["gnome-system-monitor"]
この設定ファイルを書く際に、こちらのページがかなり参考になりました。特に、中盤の「8を引く必要がある」という部分はまったく分かっていなかったので、この記事が無かったら、キーマップの設定を諦めていたところでした。著者様、ありがとうございました。
この設定ファイルでは、CapsLockに半角/全角を割り当てて、(上手くは動きませんでしたが、)Ctrl+Shift+Escにgnome-system-monitor
というコマンドの実行を割り当てています。一応、上の方から解説します。
keypress_delay_ms: 20
は、keypress_delay_ms: 20
と書いた方が良いという記事を読んだので、一応書いています。同記事によると、それはWaylandのバグなのだそうで、そのバグが解消されたら、この行は必要ないということになります。
次のkeymapは、そこがmodmapだとエラーが起きて動かなかったため、keymapにしています。
exact_match: true
は、これが無いとCapsLockが思ったとおりの動作をしてくれなかったので書いています。
remap:
以下がキーマップの定義部分です。
ここでは、CapsLockにGraveを割り当てています。もしかしたら、そこはZenkakuHankakuとかでないといけないのではないかと思った方もいらっしゃるかもしれませんが、これでCapsLockに半角/全角キーを割り当てることができています(僕の環境では)。
xevで半角/全角キーのKeycodeを調べたところ、49となっていました。なので、参考ページに書いてあったとおり、xremapの設定ファイルでは、そこから8を引いたキーを割り当てる必要があります。
つまり、41が割り当てられているキーを割り当てることになります。xremapのREADME.mdに書いてある通り、どのキーにどの数値が割り当てられているかを、ここで調べます。すると、41が割り当てられている文字列はGraveだったので、上記の設定ではCapsLockにGraveを割り当てています。
そして、CapsLockの下に、Ctrl+Shift+Escでgnome-system-monitorを起動するように設定を書いています(のつもりです)。しかし、こちらはなぜか上手く動きませんでした。
まぁ、xremapで設定することにこだわりがあるわけではありませんし、早くLinuxを使い倒したいと思ったので、あまりよく調べないままに別の手段に切り替えました。
その別の手段とは、SettingsのKeyboard欄にあるKeyboard Shortcutで、Custom Shortcutを追加して、Ctrl+Shift+Mでgnome-system-monitorが起動するようにするというものです。
ここまでを読んでいただければ分かるかと思いますが、結構行きあたりばったりに設定ファイルを書いています。なので、よく理解していませんし、なんならxremapのREADME.mdすら、あまり読んでいません。
なので、あくまでも参考程度にお願いします。
現状では、とりあえず違和感なく使えるようにしたいと思っているだけなので当分はこれで良しとしておきます。ですが、いつか気になってきたときは、もう少し調べてみて、設定を頑張ってみようと思います。
xremapをdaemon化する
xremapの設定を書けたら、それをconfig.ymlなどという名前で保存します。そして、次のようなコマンドを実行します。
sudo xremap config.yml
すると、xremapが起動されて、その後ユーザーが入力できない状態が続きます。その状態のときに、例えばgeditなどを起動して、CapsLockの機能を試してみてください。CapsLockが目標通りの動作となっているはずです。
もしかしたら、xremapの権限を変更しなければ、エラーが起きて「xremapなんて見つからないぞ」と言われるかもしれません。その場合は、chmodコマンドで実行権限を与えてください。僕の場合はすべてのユーザーに対してchmodコマンドで実行権限を与えたら上手く行きました。しかし、無闇に実行権限を与えるのは如何なものかという気もするので、これはもしかしたら推奨されない操作の可能性もあります。
xremapを起動してユーザーの入力を受け付けなくなっていても、Ctrl+cを押せば強制的に終了させられます。Ctrl+cでxremapを終了すると、CapsLockの動作が元に戻ります。
つまりxremapが起動しているときは、config.ymlに書いた設定に基づいてキーマップが変更されて、xremapが起動していなければ、config.ymlに書いた設定に関係なく、デフォルトの動作になるということですね。
先程のコマンドを実行したときは、xremapがフォアグラウンドで処理されたために、ターミナルがユーザーからの入力を受け付けなくなりました。しかし、xremapがバックグラウンドで処理されていれば、ユーザーからの入力を受け付けなくなるとことはありません。
ということで、またまたコチラのページを参考に、systemctlに登録して、毎回PCが起動されると同時に、xremapがconfig.ymlを読み込んで起動されるようにしました。これなら、xremapがバックグラウンドで実行されるので、入力がロックされることもありません。
僕は参考ページの手順をそのまま真似すれば上手く行ったので、ここでは割愛します(参考ページをご参照ください)。
まとめ
Ubuntu22.04LTSにはディスプレイサーバーとしてWaylandが採用されているということでした。
そして、WaylandでPCを触っていこうと決めた以上は、xmodmapもxkbも使えなさそうだということで、xremapを利用しました。
その設定ファイルでは、xevでKeycodeを確認して、そのキーコードから8を引いた値を割り当てられている名前を利用する必要があることには注意が必要です。
そのため、CapsLockにZenkakuHankakuを割り当てたいのに、Graveを指定するという一見すると意味不明な設定となっているのでした。
P.S.
やはり、Linux(Ubuntuですが)はWindowsとは違ってディレクトリ構造が分かりやすくていいですね。どこに何があるかが明確になっていると、自分がしっかりとPCを弄っているという操縦感が得られて楽しいです。
それと、Windowsとは比べ物にならないほど、コマンドラインツールが充実しているのも僕としてはありがたいポイントです。
それと、Linuxの自由度の高さもいいですよね。おかげで様々な設定を自分でしなければならないのですが、それも僕としては、ブラックボックスが小さくなるような感じがして好きです(もしかしたら、これも操縦感につながっているのかもしれません)。
P.P.S.
予想以上にLinuxが楽しくて、今はLinuxを色々と弄り回しています。
なので、しばらくはLinuxネタが続くと思います。今はUbuntu上でNeovim環境を作っているところなので、次はUbuntu上にNeovimをインストールしたり、設定ファイルを書いたりといった記事になると思います。
とりあえず当面の目標は、C++をごりごり書いて動かせるような環境を作ることです。
環境構築が終わったらネットワーク関係に手を出したい。