«前の日(01-27) 最新 次の日(01-29)» 追記

meta's blog - The Power To Serve

筆者について

FreeBSDを通じてOSSにささかな貢献を。

OSS活動をご支援いただける方を募集しています


2015-01-28 xrdp がキー配列を適用するしくみ

xrdp がキー配列を適用するしくみ

この記事を書いた時点でのキー配列適用のしくみをメモ。情報は不正確である可能性があります。また、VNC をバックエンドに使う機能は将来削除される予定であるため、VNC を使った場合の挙動には触れません。

本記事中では RDP のプロトコルと各実装を区別するため、明確にプロトコルを表すときは頭痛が痛くても RDP プロトコルと呼びます。Windows に付属する RDP クライアントソフトウェアのことは、その実行ファイルの名前を取って mstsc または mstsc.exe と呼びます。どの実装か特定せずにクライアントソフトウェアを表すときは、クライアントまたは RDP クライアント と呼びます。

xrdp がキー配列を適用する流れは大まかに次のような流れになっていて、本記事でもこの通りに順を追ってメモします。

  1. クライアントから送られてくるキーボード種別情報を読み込む
  2. 対応するキー配列のキーマップファイルを読み込む
  3. X11 にキー配列を適用する

クライアントからキー配列情報の受け取り

RDP プロトコルにはクライアントからサーバへクライアントのキーボード種別を送信するしくみがあり、xrdp はまずクライアントから送られてきたキーボード種別情報を受け取ります。キーボード種別は 0xe0210411 といった16進数の値で送られます。 クライアントから受け取ったクライアント情報は xrdp_client_info (common/xrdp_client_info.h)という構造体に格納されていて、キーボード種別は layout という int 型の変数に入っています。

実際にどの部分のコードでキー配列情報を受け取って xrdp_client_info に格納しているのかは調査中。

キーマップファイルの読み込み

次に、対応するキー配列のキーマップファイルを読み込みます。キーマップファイルは通常 /etc/xrdp 以下に km-*.ini という名前で存在します。キーマップファイルの仕様は genkeymap/readme.txt に書かれています。

キーマップファイルの各行は以下の様になっていて、最初の38は X11 のキーのスキャンコードです。2番目の97は KeySym 値です。3番目の97は Unicode のコード番号です。値はすべて10進数です。

[noshift]
Key38=97:97

上の例でいくと、スキャンコード38は A キー、KeySym 値も A の値、そして Unicode で a の文字コード番号である97が定義されています。つまり、A キーを単独で押すと小文字の a が出ると定義されています。これをキーの数だけ、同時に押す modifier キー (Shift,Ctrl,Alt など)の数だけ繰り替えして定義されているのがキーマップファイルです。

modifier キーを併用する部分を以下の様に書きかえると、Shift + A で小文字の z になるという定義になります。

[shift]
Key38=122:122

このようにキーマップファイルを書き換えることで、A を単独で押すと小文字の a だが、Shift と一緒に押すと小文字の z になるという風に、自在に定義することができます。もちろん実際には、Shift + A は大文字の A となるように定義されています。

キーマップファイルの仕様の話に脱線しましたが、実際にキーマップファイルをパースして読み込んでいるのは xrdp/lang.c:224 あたりです。

X11 側にキー配列を適用する

最後に、実際にクライアント側から送られてきたキー配列を X11 に適用し、デスクトップ環境のキー配列が変更されるのがこの部分です。現在のxrdp では xrdp_keyboard.ini という設定ファイルが導入されています。クライアントから送られてきたキー配列が、X11 上でどの model, layout, variant に対応するかを記述するファイルです。

バックエンドに x11rdp と xorg-driver-rdp (仮称) のどちらを使っているかによって実際に走る処理のコードは違いますが、xorg-driver-rdp は調査中なので X11rdp のみ触れます。

X11rdp のキー配列適用部分の処理
xorg/X11R7.6/rdp/rdpinput.c:283

このコードにより setxkbmap でキー配列を設定するのと同じような処理が走り、キー配列が設定されます。実際の処理の流れは以下のような感じです。

  1. クライアントからキー配列情報 0xe0010411 が送られてくる
  2. xrdp_keyboard.ini から対応する model, layout, variant を探す
  3. 0xe0010411 は rdp_layout_jp2 に対応する
  4. rdp_keyboard_jp セクションを見に行く
  5. model=jp106, layout=jp であることがわかる
  6. "setxkbmap -moddel jp106 -layout jp" コマンドを実行したのと同じような処理が走る
  7. キー配列が日本語106キーボードになる

このような処理を経て、RDP クライアント側のキー配列がサーバ側にも伝わり、クライアント側とサーバ側のキー配列を一致させています。