GNOME Remote Desktopで日本語キーボードがうまく動かない時のメモ

Windows 11の日本語109キーボードからGNOME Remote DesktopへRDP接続した時に、円記号キー、全角/半角キー、テンキーが期待通り動かなかった件の原因とGentooでのローカルパッチを整理した。

GNOME Remote Desktopで日本語キーボードがうまく動かない時のメモ

Windows 11から Linuxデスクトップへ RDP接続したい場合、GNOMEには gnome-remote-desktop という標準のリモートデスクトップ機能がある。いわゆる xrdp ではなく、GNOME自身が持っている RDPサーバー機能を使う方法だ。

これを使って当社ではいわゆるVDIのようにして業務を行っている。VDI(Virtual Desktop Infrastructure)は、業務用のデスクトップ環境を手元のPCではなく、社内サーバーやクラウド上の仮想マシンで動かす仕組みで、利用者はノートPCやタブレットなどからリモートデスクトップで接続し、画面・キーボード・マウスだけを手元で操作する。実際のアプリケーションやデータ処理は接続先の仮想デスクトップ側で行われる。

この方式にすると、端末側に業務データをできるだけ残さずに済み、PCの入れ替えや故障時にも作業環境を復旧しやすい。また、Windows、Linux、macOSなど手元の端末が違っても、同じ業務環境へ接続できるため、小規模な会社でも運用をそろえやすいのが利点だ。各個人の使用する端末からはLinuxデスクトップへRDPでログインし、どこからでも統一された環境で作業ができる。

RDP/VDIで社内のLinuxデスクトップ環境へ接続して業務を行うイメージ

さて、これ自体は便利なのだが、Windows 11の日本語109キー配列キーボードから接続すると、いくつかのキー入力が期待通りに動かなかった。

手元で確認した環境は次の通り。

この記事では、手元で踏んだ問題とローカルパッチでの回避をまとめておく。FreeRDPや GNOME Remote Desktop本体で正式に修正されれば不要になる内容なので、あくまで現時点の作業メモとして読んでほしい。

ここで紹介しているパッチは、手元の Gentoo環境での回避策です。ディストリビューションやパッケージバージョンによって事情が変わる可能性があります。

問題1: 円記号キーとパイプが入力できない

日本語キーボードの ¥ / \ キーを押しても何も入力されなかったり、Shift+¥| が入力できなかったりする。

ログには次のようなメッセージが出ることがある。

Unknown/invalid virtual device key 0x0 pressed

原因は大きく2層に分かれていた。

まず、古い gnome-remote-desktop ではクライアントのキーボード種別を IBM Enhanced、つまり type 4 として固定的に扱っていた。日本語キーボードは type 7 なので、スキャンコードの解釈がずれる。この点は gnome-remote-desktop 側で修正されており、Portage上では少なくとも gnome-remote-desktop-49.2 には含まれている。

ただし、それだけではまだ足りなかった。FreeRDP側の日本語キーボードテーブルで、円記号キーに相当する RDPスキャンコード 0x7D の仮想キーコードが VK_NONE になっていた。

#define KBD7_T7D VK_NONE

このため、RDPスキャンコード 0x7D が有効なキーとして変換されず、GNOME側に正しいキーイベントが届かない。

手元では、これを VK_OEM_8 に変えることで KEY_YEN として扱われ、日本語レイアウト上で ¥ / \ と Shift時の | が期待通り入力できるようになった。

--- a/winpr/include/winpr/input.h
+++ b/winpr/include/winpr/input.h
@@ -675,7 +675,7 @@
 #define KBD7_T7A VK_NONE
 #define KBD7_T7B VK_OEM_PA1
 #define KBD7_T7C VK_TAB
-#define KBD7_T7D VK_NONE
+#define KBD7_T7D VK_OEM_8
 #define KBD7_T7E VK_ABNT_C2
 #define KBD7_T7F VK_OEM_PA2

Gentooでは、たとえば次の場所にパッチを置いて emerge net-misc/freerdp すれば、ビルド時に自動適用される。

/etc/portage/patches/net-misc/freerdp/japanese-kbd-yen-key.patch

問題2: 全角/半角キーで入力ソースが連続切り替えされる

GNOMEの「設定」から、入力ソースの切り替えに全角/半角キーを割り当てると、1回押しただけで入力ソースが連続的に切り替わり続けることがあった。環境によっては、全く反応しないように見える場合もある。

ローカル接続では問題なく、RDP経由の時だけ発生する。

調べてみると、Windows RDPでの全角/半角キーのイベント列が少し特殊だった。通常のキーは press と release を送るが、全角/半角キーでは次のような並びになる。

1. release-only
2. press
3. release

gnome-remote-desktop は、内部的に「押されているキー」の集合を持っている。そこに存在しないキーの release は無視する設計になっているため、この release-only を起点にする特殊な並びと相性が悪い。

手元では、release-only から始まるキーを一時的に toggle key として扱い、後続の press で press+release を1回だけ発行するようにして回避した。

ロジックとしては次のような状態を持たせる。

処理の流れはこうなる。

release-only受信
  -> modifier系なら無視
  -> toggle中なら最後のreleaseとして消費し、次回のpendingも予約
  -> それ以外なら pending_toggle に登録

press受信
  -> pending_toggle にあれば press+release を1回だけ発行
  -> それ以外は通常キーとして処理

実際のデバッグでは、GNOME Remote Desktop本体ではなく handover側のユーザーサービスを見る。

G_MESSAGES_DEBUG=all journalctl --user -f -u gnome-remote-desktop-handover.service

Gentooでローカルパッチとして持つなら、たとえば次の場所に置く。

/etc/portage/patches/net-misc/gnome-remote-desktop/zenkaku-hankaku.patch

この回避は「押されていないキーの release が先に来る」という条件でだけ動くため、通常のキー入力にはほぼ影響しないはず。ただし upstream に提案するなら、日本語キーボードの時だけに限定するなど、もう少し明示的な条件を入れたほうがよさそうだ。

問題3: テンキーの数字が入力できない

もうひとつ困ったのがテンキーだった。NumLockの状態に関係なく、テンキーの 0 から 9 と小数点が数字として入力できない。

テンキーの /*-+、Enter は動くが、数字キーはカーソル移動や Home / End などとして扱われてしまう。

原因は FreeRDPの日本語キーボード用テーブルにあった。KBD7、つまり日本語キーボード type 7 の定義で、テンキーのスキャンコードが VK_NUMPAD* ではなく VK_HOMEVK_UP などに直接割り当てられている。

#define KBD7_T47 VK_HOME    /* テンキー7 */
#define KBD7_T48 VK_UP      /* テンキー8 */
#define KBD7_T49 VK_PRIOR   /* テンキー9 */

これだと NumLockの状態を見て数字にする余地がなく、常にナビゲーションキーとして処理される。

手元では、標準キーボード側の扱いと同じように VK_NUMPAD* へ戻すことで解消した。

--- a/winpr/include/winpr/input.h
+++ b/winpr/include/winpr/input.h
@@ -621,19 +621,19 @@
 #define KBD7_T44 VK_F10
 #define KBD7_T45 VK_NUMLOCK
 #define KBD7_T46 VK_SCROLL
-#define KBD7_T47 VK_HOME
-#define KBD7_T48 VK_UP
-#define KBD7_T49 VK_PRIOR
+#define KBD7_T47 VK_NUMPAD7 /* VK_HOME */
+#define KBD7_T48 VK_NUMPAD8 /* VK_UP */
+#define KBD7_T49 VK_NUMPAD9 /* VK_PRIOR */
 #define KBD7_T4A VK_SUBTRACT
-#define KBD7_T4B VK_LEFT
-#define KBD7_T4C VK_CLEAR
-#define KBD7_T4D VK_RIGHT
+#define KBD7_T4B VK_NUMPAD4 /* VK_LEFT */
+#define KBD7_T4C VK_NUMPAD5 /* VK_CLEAR */
+#define KBD7_T4D VK_NUMPAD6 /* VK_RIGHT */
 #define KBD7_T4E VK_ADD
-#define KBD7_T4F VK_END
-#define KBD7_T50 VK_DOWN
-#define KBD7_T51 VK_NEXT
-#define KBD7_T52 VK_INSERT
-#define KBD7_T53 VK_DELETE
+#define KBD7_T4F VK_NUMPAD1 /* VK_END */
+#define KBD7_T50 VK_NUMPAD2 /* VK_DOWN */
+#define KBD7_T51 VK_NUMPAD3 /* VK_NEXT */
+#define KBD7_T52 VK_NUMPAD0 /* VK_INSERT */
+#define KBD7_T53 VK_DECIMAL /* VK_DELETE */
 #define KBD7_T54 VK_SNAPSHOT
 #define KBD7_T55 VK_NONE
 #define KBD7_T56 VK_OEM_102

このパッチも FreeRDP側なので、Gentooでは次のような場所に置ける。

/etc/portage/patches/net-misc/freerdp/japanese-kbd-numpad.patch

円記号キーのパッチと同じ winpr/include/winpr/input.h を触るが、変更箇所は離れているので、少なくとも手元では同時に適用できた。

NumLockがローカルとリモートで逆に見える場合

RDP接続時に NumLockの ON/OFF がクライアント側とリモート側で逆に見える場合は、リモート側の GNOMEセッションで次の設定を入れると解消することがある。

gsettings set org.gnome.desktop.peripherals.keyboard remember-numlock-state false

これはユーザーごとの設定なので、必要なユーザーで実行する。

まとめ

手元で必要になったローカルパッチは次の3つ。

/etc/portage/patches/net-misc/freerdp/japanese-kbd-yen-key.patch
/etc/portage/patches/net-misc/freerdp/japanese-kbd-numpad.patch
/etc/portage/patches/net-misc/gnome-remote-desktop/zenkaku-hankaku.patch

整理すると、問題は次のようになる。

症状 対象 回避
¥ / \ / ` ` が入力できない FreeRDP
全角/半角キーで入力ソースが連続切り替えされる GNOME Remote Desktop release-only から始まる toggle key を特別扱いする
テンキー数字がカーソルキー扱いになる FreeRDP KBD7のテンキー定義を VK_NUMPAD* に戻す

日本語キーボードまわりは、RDPクライアント、FreeRDP、GNOME Remote Desktop、Linux側のキーコード変換が重なっていて、どこか一箇所だけ見ても原因が分かりにくい。今回の件も、GNOME側の修正でクライアント申告のキーボード種別を正しく見るようになった結果、今度は FreeRDP側の日本語キーボードテーブルの問題が表に出てきた、という形だった。

正式な修正が入るまでは、Gentooの /etc/portage/patches にローカルパッチとして置いておくのが扱いやすい。

関連記事

当社代表のデスクトップ(※)を常時ライブ配信中

※ライブ配信専用PC

OSSの検証や自社用ツールの開発といった公開できる作業に限り、 ライブ配信専用PC上で行っています。常時配信ですのでいつでもお気軽にチャットメッセージ(公開)を残していって下さい。