torutkのブログ

ソフトウェア・エンジニアのブログ

JavaFXのSwingNodeがJavaFXのイベントをSwingのイベントに変換しているあたり(続々々)

JavaFXのSwingNodeがJavaFXのイベントをSwingのイベントに変換しているあたり(続々) - torutkのブログ
の続きです。

タッチパネル操作を認識する*1プログラムと、タッチパネル操作を認識しない*2プログラムに対するWindows OSからプログラムへ発行される入力操作に関するWindowsメッセージを調べてみました。
調査に使用したのはVisual Studio付属のSpy++ツールです。

タッチパネル操作を認識するプログラム宛に発行されるWindowsメッセージ

JavaFXプログラムを動かし、spy++ツールでJavaFXプログラムを指定してWindowsメッセージのログを取得しました。

タップ操作

タップ操作(画面上を1本の指で接触して離す操作)をした際にWindows OSからJavaFXプログラムに発行されたWindowsメッセージ(WM_TOUCH*、WM_MOUSE*、WM_?BUTTON*)です。

Windowsメッセージ 属性 備考
WM_TOUCH nTouchPoints:1
: : 10個程度発行
WM_MOUSEMOVE
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_MOUSEMOVE

1点TOUCHイベントが数個発生してから、マウスの左ボタン押し下げ/離したイベントが発生しています。

長押し操作

長押し操作(画面上を1本の指で接触し1秒間そのままにしてから離す操作)をした際にWindows OSからJavaFXプログラムに発行されたWindowsメッセージ(WM_TOUCH*、WM_MOUSE*、WM_?BUTTON*)です。

Windowsメッセージ 属性 備考
WM_TOUCH nTouchPoints:1
: : 100個程度発行
WM_MOUSEMOVE
WM_RBUTTONDOWN 画面上に黒枠の矩形(指より大きい程度)が表示された
WM_RBUTTONUP
WM_MOUSEMOVE

1点TOUCHイベントが百個程度発生してから、マウスの右ボタン押し下げ/離したイベントが発生しています。

ピンチ操作

ピンチ操作(画面上を2本の指で接触し2本の指を互いに近づける操作)をした際にWindows OSからJavaFXプログラムに発行されたWindowsメッセージ(WM_TOUCH*、WM_MOUSE*、WM_?BUTTON*)です。

Windowsメッセージ 属性 備考
WM_TOUCH nTouchPoints:1
: : 数個程度発行
WM_TOUCH nTouchPoints:2
: : 10個程度発行
WM_MOUSEMOVE
WM_LBUTTONDOWN
WM_MOUSEMOVE fwKeys:MK_LBUTTON
WM_TOUCH nTouchPoints:2
: : 10数個程度発行
WM_MOUSEMOVE fwKeys:MK_LBUTTON
WM_TOUCH nTouchPoints:2
: WM_MOUSEMOVEとWM_TOUCHのペアが30個程度連続発行
WM_TOUCH nTouchPoints:1
: : 数個程度発行
WM_LBUTTONUP
WM_MOUSEMOVE

マウス左ボタン押下に続いて、2点TOUCHイベントとWM_MOUSEMOVEイベントが繰り返し発生しています。その後、左ボタンが離されたイベントで終わります。

スライド操作

スライド操作(画面上を1本の指で接触したまま移動させる操作)をした際にWindows OSからJavaFXプログラムに発行されたWindowsメッセージ(WM_TOUCH*、WM_MOUSE*、WM_?BUTTON*)です。

Windowsメッセージ 属性 備考
WM_TOUCH nTouchPoints:1
: : 10個程度発行
WM_MOUSEMOVE
WM_LBUTTONDOWN
WM_MOUSEMOVE fwKeys:MK_LBUTTON
WM_TOUCH nTouchPoints:1
: WM_MOUSEMOVEとWM_TOUCHのペアが数十個程度連続発行
WM_LBUTTONUP
WM_MOUSEMOVE

タッチパネル操作を認識しないプログラム宛に発行されるWindowsメッセージ

UnregisterTouchWindow APIを呼ぶJavaFXプログラムを動かし、spy++ツールでJavaFXプログラムを指定してWindowsメッセージのログを取得しました。

タップ操作

タップ操作(画面上を1本の指で接触して離す操作)をした際にWindows OSからJavaFXプログラムに発行されたWindowsメッセージ(WM_TOUCH*、WM_MOUSE*、WM_?BUTTON*)です。

Windowsメッセージ 属性 備考
WM_MOUSEMOVE
WM_LBUTTONDOWN
WM_LBUTTONUP
長押し操作

長押し操作(画面上を1本の指で接触し1秒間そのままにしてから離す操作)をした際にWindows OSからJavaFXプログラムに発行されたWindowsメッセージ(WM_TOUCH*、WM_MOUSE*、WM_?BUTTON*)です。

Windowsメッセージ 属性 備考
WM_MOUSEMOVE
WM_RBUTTONDOWN
WM_RBUTTONUP
ピンチ操作

ピンチ操作(画面上を2本の指で接触し2本の指を互いに近づける操作)をした際にWindows OSからJavaFXプログラムに発行されたWindowsメッセージ(WM_TOUCH*、WM_MOUSE*、WM_?BUTTON*)です。

Windowsメッセージ 属性 備考
WM_GESTURE BEGIN
WM_GESTURE ZOOM
: :
WM_MOUSELEAVE
WM_MOUSEMOVE
WM_GESTURE ZOOM
: :
WM_MOUSEWHEEL MK_CONTROL
WM_MOUSEMOVE MK_CONTROL
WM_GESTURE ZOOM
: :
WM_MOUSEWHEEL MK_CONTROL
WM_MOUSEMOVE MK_CONTROL
スライド操作

スライド操作(画面上を1本の指で接触したまま移動させる操作)をした際にWindows OSからJavaFXプログラムに発行されたWindowsメッセージ(WM_TOUCH*、WM_MOUSE*、WM_?BUTTON*)です。

Windowsメッセージ 属性 備考
WM_MOUSEMOVE
WM_LBUTTONDOWN
WM_MOUSEMOVE
: :
WM_LBUTTONUP
WM_MOUSEMOVE

JavaFXの内部でのタッチ操作イベントを捌いている箇所を調査

modules/graphics/src/main/native-glass/win/GlassWindow.cpp においてメンバー関数WindProcでWindowsメッセージの場合分けと処理(switch文)をしています。WM_TOUCHの場合の処理を抜粋します。

        case WM_TOUCH:
            if (IsEnabled()) {
                if (activeTouchWindow == 0 || activeTouchWindow == GetHWND()) {
                    if(HandleViewTouchEvent(GetHWND(), msg, wParam, lParam) > 0) {
                        activeTouchWindow = GetHWND();
                    } else {
                        activeTouchWindow = 0;
                    }
                } 
                return 0;
            }
            break;

modules/graphics/src/main/native-glass/win/ViewContainer.cpp において、ViewContainer::HandleViewTouchEventメンバー関数が定義されています。

  • タッチ点数を取得(最大10)
  • GetTouchInputInfo APIでタッチ情報を取得
  • 前回のタッチ点数とタッチ情報と今回のタッチ点数とタッチ情報を突合せていろいろと処理・・・
  • タッチ点数が0でない(正の数)であれば、ViewContainer::NotifyTouchInputメンバー関数を呼ぶ

modules/graphics/src/main/native-glass/win/ViewContainer.cpp において、ViewContainer::NotifyTouchInputメンバー関数が定義されています。

  • com.sun.glass.ui.win.WinGestureSupport(Javaのクラス)のnotifyBeginTouchEventを呼ぶ
    • com.sun.glass.ui.TouchInputSupportのnotifyBeginTouchEventを呼ぶ
  • com.sun.glass.ui.win.WinGestureSupport(Javaのクラス)のnotifyNextTouchEventを呼ぶ(タッチ点数の数だけ)
    • com.sun.glass.ui.TouchInputSupportのnotifyNextTouchEventを呼ぶ
  • com.sun.glass.ui.win.WinGestureSupport(Javaのクラス)のnotifyEndTouchEventを呼ぶ
    • com.sun.glass.ui.TouchInputSupportのnotifyEndTouchEventを呼ぶ
    • com.sun.glass.ui.win.WinGestureSupportのgestureFinishedを呼ぶ
      • ジェスチャがスクロールか、回転か、ズームかを判定し、com.sun.glass.ui.GestureSupportのhandleScrollingEnd、handleRotationEnd、handleZoomingEndを呼ぶ

ここから先の追跡が困難ですが、JDK 8u60に付属のjavafx-srcを展開し、中にあるcom.sun.javafx.tk.quantum.GestureRecognizers が、GlassTouchEventListenerを実装しており、また、notifyBeginTouchEvent、notifyNextTouchEvent、notifyEndTouchEventメソッドを定義しています。

ジェスチャーの識別については、com.sun.javafx.tk.quantumパッケージに、ScrollGestureRecognizer、ZoomGestureRecognizer、SwipeGestureRecognizerなどのクラスが用意されており、これらにTouchイベントの発生状況からどんなジェスチャーかを判定しているように思われます。

*1:RegisterTouchWindow APIを呼んだ

*2:RegisterTouchWindow APIを呼んでいない、あるいは呼んでいた場合にはその後にUnregisterTouchWindow APIを呼んだ