xrdpとmacOSの組み合わせでキーボード判定

xrdpの環境にmacOS端末でログインすると結構な確率でキーボード判定がおかしくなりませんか?

macOSでRDPするにはMicrosoft謹製のwindows.appを使うわけなのですが、どうもxrdpに送られてくるキーボードレイアウトの情報がおかしい、というか無いに等しい。

これがWindows機ならばある程度の種類を送ってきてくれるので、それに適したレイアウトで操作できるわけなのですが、Windows.appから送られてくる情報は常に0x00000000。

キーマップは0x00000411.tomlをコピーして0x00000000.tomlを作ってしまうことで誤魔化しは効くものの、どういうわけかusキー・日本語キーの判定は接続するたびに違っていたりで、少なくとも私の個人持ちのMacBookではUSキー判定されたり日本語キー判定されたり。

接続自体はスムーズなのに、いざ「@」や「¥」を入力しようとすると違うレイアウトになっていることに気づいて接続し直す羽目になるのがどうも憂鬱。

・というわけでもう作っちゃえ

というわけで、GUIで設定変更できるツールをさくさくっと。

ついでに接続してきた端末名や解像度と設定内容を記録しておいて、自動実行でも設定できるように。

[ keyboard-switcher.sh ]

#!/bin/bash

# --- 実行モード判定 ---
AUTO_MODE=false

if [[ "$1" == "--auto" ]]; then
    AUTO_MODE=true
fi

# --- 設定保存先・識別情報取得 ---
CONFIG_DIR="$HOME/.config/keyboard_layouts"
AUTOSTART_DIR="$HOME/.config/autostart"
AUTOSTART_FILE="$AUTOSTART_DIR/keyboard-switcher.desktop"
CURRENT_UID=$(id -u)

mkdir -p "$CONFIG_DIR"
mkdir -p "$AUTOSTART_DIR"

resolution=$(xdpyinfo | grep dimensions | awk '{print $2}')
hostname=$(xprop -root | grep Xdpy | cut -d\" -f2 | cut -d@ -f2)

[[ -z "$resolution" ]] && resolution="unknown_resolution"
[[ -z "$hostname" ]] && hostname="unknown_host"

safe_id=$(echo "${hostname}_${resolution}" | tr -cs '[:alnum:]_-' '_')
CONFIG_FILE="$CONFIG_DIR/${safe_id}.conf"

# --- 現在のキーボードレイアウトを取得 ---
current_layout=$(setxkbmap -query | grep layout | awk '{print $2}')

# --- 自動モード: GUIなしで適用する ---
if $AUTO_MODE; then
    if [[ -f "$CONFIG_FILE" ]]; then
        saved_layout=$(cat "$CONFIG_FILE")
        if [[ "$saved_layout" == "us" || "$saved_layout" == "jp" ]]; then
            setxkbmap "$saved_layout"
            echo "[INFO] 自動実行: '${saved_layout}' を適用しました (${safe_id})"
            if ! ps -u $CURRENT_UID -o comm | grep -q "^fcitx5$"; then
               fcitx5 -d
            fi
            exit 0
        fi
    fi
    echo "[INFO] 自動実行: 設定が見つからなかったため変更なし"
    exit 0
fi

# --- 手動実行: GUIで選択 ---
us_selected=FALSE
jp_selected=FALSE

if [[ -f "$CONFIG_FILE" ]]; then
    saved_layout=$(cat "$CONFIG_FILE")
    if [[ "$saved_layout" == "us" ]]; then
        us_selected=TRUE
    elif [[ "$saved_layout" == "jp" ]]; then
        jp_selected=TRUE
    fi
else
    if [[ "$current_layout" == "jp" ]]; then
        jp_selected=TRUE
    else
        us_selected=TRUE
    fi
fi

layout=$(GSK_RENDERER=cairo zenity --list \
    --title="キーボードレイアウトの選択" \
    --text="使用するキーボードレイアウトを選んでください\n(端末: ${hostname}, 解像度: ${resolution})" \
    --radiolist \
    --column="選択" --column="レイアウト" \
    $us_selected "us (英語)" \
    $jp_selected "jp (日本語)" \
    FALSE "削除(設定をリセット)")

# --- ユーザーが削除を選択した場合 ---
if [[ "$layout" == "削除(設定をリセット)" ]]; then
    GSK_RENDERER=cairo zenity --question --title="設定削除" --text="自動実行設定とキーボード設定を削除しますか?"
    if [[ $? -eq 0 ]]; then
        rm -f "$AUTOSTART_FILE"
        rm -rf "$CONFIG_DIR"
        GSK_RENDERER=cairo zenity --info --text="削除が完了しました。"
        echo "[INFO] 削除が完了しました。"
    else
        echo "[INFO] 削除をキャンセルしました。"
    fi
    exit 0
fi

# --- キーボードレイアウトの適用 ---
if [[ "$layout" == "us (英語)" ]]; then
    setxkbmap us
    echo "us" > "$CONFIG_FILE"
    if ! ps -u $CURRENT_UID -o comm | grep -q "^fcitx5$"; then
        fcitx5 -d
    fi
elif [[ "$layout" == "jp (日本語)" ]]; then
    setxkbmap jp
    echo "jp" > "$CONFIG_FILE"
    if ! ps -u $CURRENT_UID -o comm | grep -q "^fcitx5$"; then
        fcitx5 -d
    fi
else
    GSK_RENDERER=cairo zenity --info --text="レイアウトが選択されませんでした。"
    exit 1
fi

# --- 自動起動用のデスクトップエントリーを作成 ---
# Exec行はスクリプト配置により適宜書き換え /usr/local/bin/ 推奨
cat <<EOF > "$AUTOSTART_FILE"
[Desktop Entry]
Type=Application
Exec=$HOME/keyboard-switcher.sh --auto
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
EOF

GSK_RENDERER=cairo zenity --info --text="設定内容を保存し自動実行を設定しました (${AUTOSTART_FILE})"
echo "[INFO] 設定内容を保存し自動実行を設定しました (${AUTOSTART_FILE})"

と、こんな感じで。

配置はどこでも良いけれど、実行するためには chmod +x keyboard-switcher.sh を忘れずに。

・こまかいところ

仕様的には

・自動実行時+保存情報あり:保存された情報で設定して静かに終了
・自動実行時+保存情報なし:なにもせず静かに終了
・手動実行時+保存情報あり:GUIを開き保存された情報を表示
・手動実行時+保存情報なし:GUIを開く

と言う感じで、保存情報は

~/.config/keyboard_layouts/ 以下に「ホスト名_解像度.conf」の設定ファイルを作って記憶。

ただ、実際に動かしてみるとhost名が取得できなくて unknown_host_1440x900_.confみたいな形になってしまいましたが、実用上支障なしということで。

書き忘れるところだった。
自動実行時というのをどう判定するねん、という点は –auto というオプションを付けることで判断します。

・せっかく作ったならメニューへ

せっかくGUIなツールなのに起動がいちいちCLIではもったいないので、デスクトップエントリーに以下のように追加。

[ /usr/share/applications/keyboard-switcher.desktop ]

[Desktop Entry]
Name=キーボードレイアウト切替
Exec=/usr/local/bin/keyboard-switcher.sh ←ここは環境にあわせてフルpathを!
Type=Application
Terminal=false
Icon=input-keyboard
Categories=Settings;Utility;

これでちょっと楽ができるかな?


安心安全安価なSDカードデータ復元・HDDデータ復元は
長年の信頼と実績の『株式会社パソコントラブル救助隊』へ。
https://hqsecure.net/

xrdpでカーソルキーがエンターと誤入力される件

なにやら、Linux端末からxrdpサーバーへ接続してみるとキーの反応がおかしい。

アプリケーションによってはカーソルキーの「↓」を押すとEnterキーが押されたことになってしまう様子。使用するアプリによってはかなりメンドクサイかもしれない。
※正確にはNumericEnterでテンキー側のエンターキーと認識されてる

key-event-viewerの出力結果

https://w3c.github.io/uievents/tools/key-event-viewer.html

■develop版のxrdpに変えて解決

現象を確認したのは xrdp v0.10.1でしたが、どうやらその先のv0.10.2でも解消されていないようで急遽develop版に差し替えてみることに。

サーバーにはv0.10.1をインストールした時の名残があるので

git switch –

でdevelopになっていることを確認してから

git pull

けっこう激しく変更があったようで、ダウンロードに少し時間がかかっていた。

pull後は

./bootstrap
./configure –enable-fuse –enable-mp3lame –enable-pixman
make
sudo make install

と、いつも通りの手順でインストール完了。xrdpxorgも忘れずに同じ要領で。

念のためにバージョンを確認すると v0.10.80 となっていた。

サーバーをrebootし、再起動後は無事に「↓」がArrowDownと認識されるようになりメデタシメデタシ。なんのことはない単純なバグが残っていたのだね。

key-event-viewerで正常に戻った結果

■しかしMacBookでは「_」が入らない

ここで新たな罠が。

Windows端末からログインする分にはなんの問題もなくなったのだけれど、MacOS端末からログインするとアンダースコア「_」が入らない

そのほかにも記号が刻印とずいぶんズレてしまう。

いったい誰が悪いんだろう?RDPに使っているWindowsAppが悪さしているのか?

■なぜかusキー判定

なかなか深みにはまっていってる予感。

ひとまず自分の端末がどんな値を送ってきているのか調べてみる。

sudo cat /var/log/xrdp.log

すると、直近の接続では keyboard_type=4, keyboard_subtype=0, keylayout=0x00000000 と!

私のはそんなこだわりもなく日本市場のMacBookで日本語キーボード。それなのに0x00000000が送信されていることで、受信した側のxrdpではusキー端末がログインしてきたと判定されているっぽい。

■キーボードレイアウト設定が変?

xrdpの設定なんか触れたことないぞ、とブツブツつぶやきながら設定を覗いてみると /etc/xrdp/xrdp_keyboard.ini なんてファイルがある。

でもこのファイル、中身をみても何を定義したいのだか理解しがたい構造。

あれこれ試してみてようやく、キーボードタイプやレイアウトの値を受け取って、最終的にキー配列が 「jp」 とか 「us」 とかいった値を導きだす目的のものなのかとひとまず理解した。

■本来はkm-00000406?

超絶詳しい方に聞いてみたところ、本来はMacOS(日本語キー)では0x00000406が送られてくるものらしい。でも私のはなぜか0x00000000しか出してこない。
※たまにそういうMacOS機がいるらしいとか。

そして、0x00000000を受け取ったxrdp側は、xrdp_keyboard.iniの設定に書かれている通り0x00000000に合致するものはusキーだと値を返してくるし、異なったキーマップなので日本語キーボードの刻印とはちがった記号が入力されてしまうということらしい。

ならば多少強引だけれども、/etc/xrdp/km-00000406.ini をコピーして km-00000000.iniとして置き換えてみたらどうかと試行すると、ある程度はちゃんと動作する。

でも、アンダースコアが”=”になったり、まったくなにも出なかったり。わりと困る。

■キーマップを作り直す

もういちどxrdp.logを見てみると、こんどはkm-00000000.tomlが存在しないという記録が残っていた。たしかにそんなファイルは存在しない。

キーマップってkm-????????.iniじゃないのか?と思って調べてみると確かにkm-????????.tomlも在るようで、ちょっと書式が違って人間がわかりやすい書き方である、という説明もあるものの大差ない気もするなあ。

特に今回はkm-00000000.iniを用意していたにもかかわらずログにはkm-00000000.tomlが無いと要求されているので、やむなく手探り状態でキーマップを作ってみることに。

キーマップを作製するコマンドがあるようなので以下を試してみる。

xrdp-genkeymap km-00000000.toml

これで作成されたkm-00000000.tomi を /etc/xrdp/以下に配置し、rdp接続しなおすことでキーマップが見つからないよ!っていうログは出なくなった。

しかも、ちゃんとアンダースコアが入力できるようになっているではないか(^^)素晴らしい

■とりあえずはOKとして…

当面はこれで問題なしとして、まだちょっとこだわらないといけないポイントがありそう。

と思っていたら「¥」はどこに行ったのだろうとか「\」(←環境によっては¥表示かな)はどうやって出すんだ?とかいった問題があることに気づいてしまった。

もともと私のMacBookのキーボードでは右下「ろ」にあたる位置にはバックスラッシュの割り当てがないので見逃していて、シフトキーを押しても押さなくても「_」が出るじゃないかサービス満点なキーマップだな、などと呑気なことを考えていた。

しかし本当に世の中にはキーボードの種類が多すぎる。言語がいくつもあるのだから仕方ないにしても、同じ言語圏でいくつもあるのは勘弁してほしい。
※以前ロシア語を学んでいた時もキリル文字のキーボード多いなと思ったものだが

■なんだかんだでキーマップを複製

あれこれと設定を試してみていると、どうも jp レイアウトと判定されることにこだわる必要性は低そうで、us 判定のままでも問題ない感じ。

ならば、レイアウトはwindows端末が送信してくるものを複製しちゃおう、と
km-00000411.toml を km-00000000.toml として複製

なんとなくそれだけで大丈夫そうではあるけれど、念のために xrdp_keybboard.ini にも追記。内容はMacではなくWindowsにあわせちゃう。

[rdp_layout_mac_jp]
keyboard_type=4
keyboard_subtype=0
rdp_layouts=default_rdp_layouts
layouts_map=default_layouts_map

いざ、接続してみるとちゃんと「¥」が出る!「_」も出る。そのほかの記号もちゃんと刻印通りに出ている、素晴らしい(^^)

あとはこれで、他のキー配列の端末が同じ0x00000000を送ってこないことを祈るばかり。


安心安全安価なSDカードデータ復元・HDDデータ復元は
長年の信頼と実績の『株式会社パソコントラブル救助隊』へ。
https://hqsecure.net/