スタイラスによる入力イベントを取得する


Android4.0では、スタイラスによる入力イベントを取得できるようになりました。

Androidでは、これまでもスタイラスペンによる入力時にイベントは取得できていましたが、マウスや指で端末画面をタッチ、もしくはドラッグした際に発生するイベントと同様にして扱われていました。

Android4.0では、Motion Eventから指、マウス、スタイラス、その他のいずれの入力なのかを判別することができるようになりました。
つまり、スタイラスの入力を、指やマウスとは違った入力として扱うことが可能になったということになります。

今回はMotion Eventからどのようにスタイラスとによる入力イベントを取得する方法について解説します。実機がないため、実際に確認することはできていませんが、ApiDemosのTouchpaint.javaのソースコードとそのサンプルをベースに解説を進めます。


図:ApiDemos の Touch Paintサンプル (android-14/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java)

Touch Paintサンプルは、端末(画像はエミュレータ)の画面上をマウスや指、スタイラスでドラッグすると、それぞれで違ったスタイルの線を引くことができます。

それでは続きをどうぞ

5つの”Tool Type”とその取得方法

MotionEventのgetToolType()メソッドを使用することで、“Tool Type”を取得することができます。
“Tool Type”とは名前の通り、入力に使用したツールのタイプ(指やスタイラス、マウスなど)のことを示します。

“Tool Type”には、現在以下の5つが定義されています。

表1:各種”Tool Type”とその概要

API概要
TOOL_TYPE_FINGER
TOOL_TYPE_MOUSEマウス
TOOL_TYPE_STYLUSスタイラス
TOOL_TYPE_ERASER消しゴム
TOOL_TYPE_UNKNOWNその他

実際のソースコード上でどのように使用されているのか見てみます。

[android-14/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java]

        private boolean onTouchOrHoverEvent(MotionEvent event, boolean isTouch) {
(...省略...)
                final int N = event.getHistorySize(); // N : イベント(MOVE)が発生した数
                final int P = event.getPointerCount(); // P : 画面と接触しているポイントの数
                for (int i = 0; i < N; i++) {
                    for (int j = 0; j < P; j++) {
                        paint(getPaintModeForTool(event.getToolType(j), mode),
                                event.getHistoricalX(j, i), // X座標
                                event.getHistoricalY(j, i), // Y座標
                                event.getHistoricalPressure(j, i), // 筆圧
                                event.getHistoricalTouchMajor(j, i), // 接触領域(長方形)の長い方の長さ
                                event.getHistoricalTouchMinor(j, i), // 接触領域(長方形)の短い方の長さ
                                event.getHistoricalOrientation(j, i), // スタイラスの向いている方向
                                event.getHistoricalAxisValue(MotionEvent.AXIS_DISTANCE, j, i), // スタイラスの先端と端末画面との距離
                                event.getHistoricalAxisValue(MotionEvent.AXIS_TILT, j, i)); // スタイラスと端末画面との角度
                    }
                }
(...省略...)
        }

7行目でMotion Eventから”Tool Type”を取得し、getPaintModeForTool()メソッドに渡しています。
また、14行目および15行目で、getHistoricalAxisValue()メソッドを用いてスタイラスの軸の情報を取得しています。
getHistoricalAxisValue()メソッド自体はAPI Level 12から存在していますが、引数のAXIS_DISTANCEおよびAXIS_TILTは今回新しく追加されたAPIです。

        private PaintMode getPaintModeForTool(int toolType, PaintMode defaultMode) {
            if (toolType == MotionEvent.TOOL_TYPE_ERASER) {
                return PaintMode.Erase;
            }
            return defaultMode;
        }

getPaintModeForTool()メソッドでは、渡されてきた”ToolType”から、表1に従い入力に使用されたデバイスを判別し、PaintModeとして返しています(2行目)。

        private void paint(PaintMode mode, float x, float y, float pressure,
                float major, float minor, float orientation,
                float distance, float tilt) {
(...省略...)
                switch (mode) {
(...省略...)
                    case Erase:
                        mPaint.setColor(BACKGROUND_COLOR);
                        mPaint.setAlpha(Math.min((int)(pressure * 128), 255));
                        drawOval(mCanvas, x, y, major, minor, orientation, mPaint);
                        break;
(...省略...)
                }
(...省略...)
        }

paintメソッドでは、第一引数で渡されてきたPaintModeに従って、線の描画に必要な情報をセットする処理を分けています。

“Button State”を取得する

Android4.0では、Tool Typeだけでなく、”Button State“も取得することができます。
“Button State”とは、マウスやスタイラスでの入力時に、どのボタンを押されて入力されたのかという情報のことを示します。

マウスだと右クリックと左クリック、あと中央ボタン(ホイールなど)が付いている場合があります。
スタイラスのボタンとは、例えばHTCのタブレット端末「Flyer」に付属しているスタイラスには、二つのボタンが付いています。


図:スタイラスペン参考画像
このうち片方のボタンがBUTTON_SECONDARY、もう片方がBUTTON_TERTIARYに割り当たります。

“Button State”を取得するには、MotionEventクラスのgetButtonState()メソッドを使用します。
現在getButtonState()メソッドによって取得可能なイベント情報は以下の通りです。

API概要
BUTTON_PRIMARYマウスの左(メイン)クリックによる入力
BUTTON_SECONDARYマウスの右(サブ)クリックもしくはスタイラスに付属するボタンの一つ目(メイン)
BUTTON_TERTIARYマウスの真ん中のクリックもしくはスタイラス付属のボタン2番目(サブ)
BUTTON_BACKマウスのホイールボタンを前に進める
BUTTON_FORWARDマウスのホイールボタンを後ろに進める

なお、BUTTON_SECONDARYおよびBUTTON_TERTIARYについては、マウスとボタンで共用していることに注意します。

実際にソースコードの中でどのように使われているのか見てみます。

[android-14/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java]

        private boolean onTouchOrHoverEvent(MotionEvent event, boolean isTouch) {
            final int buttonState = event.getButtonState();
            int pressedButtons = buttonState & ~mOldButtonState;
            mOldButtonState = buttonState;
(...省略...)
            if ((pressedButtons & MotionEvent.BUTTON_SECONDARY) != 0) {
                // Advance color when the right mouse button or first stylus button
                // is pressed.
                advanceColor();
            }

            if ((buttonState & MotionEvent.BUTTON_TERTIARY) != 0) {
                // Splat paint when the middle mouse button or second stylus button is pressed.
                mode = PaintMode.Splat;
            } else if (isTouch || (buttonState & MotionEvent.BUTTON_PRIMARY) != 0) {
                // Draw paint when touching or if the primary button is pressed.
                mode = PaintMode.Draw;
            } else {
                // Otherwise, do not paint anything.
                return false;
            }
(...省略...)
        }

2行目でMotionEventからgetButtonState()メソッドを使用して”Button State”を取得しています。
取得した”Button State”から、マウスやスタイラスのどのボタンを押されたのかを判別し、描く線の種類や色を変化させています(6,12,15行目)。

図:BUTTON_TERTIARY(マウス中央ボタンorスタイラスペンのサブボタン押下)イベント時に描画されるPaintMode.Splat

図:BUTTON_SECONDARY(マウス右orスタイラスメインボタン押下)イベント時に描画されるAdvanceColor

まとめ

今回、MotionEventから”Tool Type”を判別する方法と、”Button State”を判別する方法を解説しました。
これらのAPIの追加によって、スタイラスによる入力を、指やマウスによる入力と区別することができるようになります。
スタイラスによる入力を判別することができれば、ペン入力アプリにおいて、消しゴムの実装など、特殊な機能を割り当て、アドバンテージを得られます。