はじめに
みなさん VDI してますかー?
このたび CentOS 7 の VNC Viewer で、マウスの戻る・進むボタン、漢字キーを使えるように出来たので、メモを残します。
背景
個人的に VDI ぽいことをしている私は、VNC に依存した生活をしています。最近わずかに環境を変えたことで、今まで気付かなかった不自由に遭遇しました。
操作が不自由
マウスを新調したり VNC Viewer を実行する環境を CentOS 7 に変更したりしたところ、少し困ったことになりました。
- マウスの戻る・進むボタンが使えない
- 漢字キーが使えない
まず、「だっせー知らなかったのかよ!」的な感じですが、マウスボタンが無反応でしたw 買って届いて挿したら動かないw そして、CentOS 6 ではフツーに使えていた漢字キーも無反応になりましたww
原因
VNC では第9ボタン以降が使えません。これは RFB (VNC のプロトコル)の制限で、マウスボタン情報用に1オクテットしか割り当てられていないからです。
加えて TigerVNC (CentOS 7 に同梱されている VNC 実装)は第8ボタン以降が使えません。これは VNC Viewer が利用している FLTK (GUI ツールキット)の制限で、ボタンとしては第1〜3ボタンしか走査していないからです。
マウスの第1〜3ボタンは左中右ボタン、第4〜7ボタンはホイールの上下左右、第8〜9ボタンが戻る・進むボタンです。
更に、CentOS 7 同梱の VNC Viewer は漢字キーの操作情報を捨てますw なんとww これは、TigerVNC 1.3 がキー入力情報をホワイトリストで取捨選択しているからです。そもそも FLTK に「漢字キー」が定義されていないので、リストに入るはずもなく、ポイっとw
ちなみに CentOS 6 の TigerVNC 1.1 は、そんな処理してません。最新の 1.8 も、そんな処理してません。
やったこと
前述の不自由を解消するため、やったことは3つです。
- FLTK に第8〜9ボタンの定義を追加する
- VNC Viewer に第8〜9ボタンイベントを認識させ、戻るキー・進むキーイベントに変換させる
- VNC Viewer に漢字キーを捨てるのを止めさせるww
勝手に第8〜9ボタンの定義を追加する
diff -urN fltk-1.3.x-r9671/FL/Enumerations.H fltk-1.3.x-r9671-8th9th/FL/Enumerations.H
--- fltk-1.3.x-r9671/FL/Enumerations.H 2012-03-27 01:54:54.000000000 +0900
+++ fltk-1.3.x-r9671-8th9th/FL/Enumerations.H 2017-09-12 22:00:00.000000000 +0900
@@ -433,6 +433,8 @@
#define FL_BUTTON1 0x01000000 ///< Mouse button 1 is pushed
#define FL_BUTTON2 0x02000000 ///< Mouse button 2 is pushed
#define FL_BUTTON3 0x04000000 ///< Mouse button 3 is pushed
+#define FL_BUTTON8 0x08000000 ///< Mouse button 8 is pushed
+#define FL_BUTTON9 0x10000000 ///< Mouse button 9 is pushed
#define FL_BUTTONS 0x7f000000 ///< Any mouse button is pushed
#define FL_BUTTON(n) (0x00800000<<(n)) ///< Mouse button n (n > 0) is pushed
diff -urN fltk-1.3.x-r9671/src/Fl_x.cxx fltk-1.3.x-r9671-8th9th/src/Fl_x.cxx
--- fltk-1.3.x-r9671/src/Fl_x.cxx 2012-06-21 17:52:29.000000000 +0900
+++ fltk-1.3.x-r9671-8th9th/src/Fl_x.cxx 2017-09-12 22:00:00.000000000 +0900
@@ -1520,7 +1520,9 @@
Fl::e_dx = +1; // Right
event = FL_MOUSEWHEEL;
} else {
- Fl::e_state |= (FL_BUTTON1 << (xevent.xbutton.button-1));
+ Fl::e_state |= FL_BUTTON(
+ xevent.xbutton.button <= 7 ? xevent.xbutton.button : xevent.xbutton.button - 4
+ );
event = FL_PUSH;
checkdouble();
}
@@ -1570,7 +1572,9 @@
case ButtonRelease:
Fl::e_keysym = FL_Button + xevent.xbutton.button;
set_event_xy();
- Fl::e_state &= ~(FL_BUTTON1 << (xevent.xbutton.button-1));
+ Fl::e_state &= ~FL_BUTTON(
+ xevent.xbutton.button <= 7 ? xevent.xbutton.button : xevent.xbutton.button - 4
+ );
if (xevent.xbutton.button == Button4 ||
xevent.xbutton.button == Button5) return 0;
event = FL_RELEASE;
本件と関係ないですが、第4〜5ボタンのリリースイベントを捨てているところ、第6〜7ボタンも捨てないとダメな気がしますが、まぁ、もう古い実装なので。。。
(第4〜7ボタンは、ボタンイベントではなくホイールイベントとして伝達されます。)
条件演算子はインライン関数にすべきですねぇ。せっかく C++ なのに。
TigerVNC にパッチ
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 9fd849f..5b018e6 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -422,6 +422,13 @@ int Viewport::handle(int event)
}
handlePointerEvent(Point(Fl::event_x() - x(), Fl::event_y() - y()), buttonMask);
+
+ if (Fl::event_buttons() & FL_BUTTON8) {
+ handleKeyEvent(FL_Forward, FL_Forward, "", (event == FL_PUSH));
+ }
+ if (Fl::event_buttons() & FL_BUTTON9) {
+ handleKeyEvent(FL_Back, FL_Back, "", (event == FL_PUSH));
+ }
return 1;
case FL_FOCUS:
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 9fd849f..7820877 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -737,6 +737,9 @@ rdr::U32 Viewport::translateKeyEvent(int keyCode, int origKe
yCode, const char *k
case XK_Multi_key:
// Same for this...
return XK_Multi_key;
+ case XK_Zenkaku_Hankaku:
+ // pass through to control IM
+ return XK_Zenkaku_Hankaku;
}
// Unknown special key?
おわりに
RFB を拡張して純粋に第8〜9ボタンの透過伝達を実現することは、今回は見送りました。現状の改修内容だと VNC Server 側は既存のものがそのまま使える利点があります。
というか、最近はマウスボタンが16個まで認識されるようなので、もしかしたら既に RFB が拡張されているのかも。そこも特に調べませんでした。
そのぶん、バイナリパッチ並のクイックハックに収まっていると思うので、ヨシとします。