2013年9月5日木曜日

AndroidのWebViewにキーイベントを送る

AndroidのWebViewはタブレットやスマートフォン用にカスタマイズされているため、キーイベントがほとんどきません。
このため、キーボードやゲームパッドで操作するWebViewベースのAndroidアプリを作ることができません。
せっかくいろいろなUSBデバイスやBluetoothデバイスがつながるのに、これらをWebViewで利用できないなんてとても不便です。

ネットで調べても答えが見つからなかったのでいろいろ考えてキーイベントをきっちっと受け取れるWebViewを作ってみました。

ActivityのdispatchKeyEvent()にはイベントがくるので、webview.loadUrl()でJavaScriptを実行させます。
javaScript側ではcreateEvent()でイベントを作って、initEvent()でキーボードイベントを作成、最後にdispatchEvent()でイベントを送信します。

とりあえず方向キーのキーイベントを送るサンプルを作ってみました。
これでどんなキーイベントもWebViewに送れます。

------------------------------------------------------------------------

public class SomeMain extends Activity{

public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    webview.getSettings().setJavaScriptEnabled(true);
    webview.loadUrl("file:///android_asset/index.html");
    setContentView(webview);
}

public boolean dispatchKeyEvent(KeyEvent e) {
    int keyCode=e.getKeyCode();
    if (e.getAction() == KeyEvent.ACTION_UP) {
        switch(keyCode){
        case 19:
            webview.loadUrl("javascript: "
                +"try{"
                +"var evt = document.createEvent('Events');"
                +"evt.initEvent('keydown', true, true);"
                +"evt.keyCode = 38;"
                +"window.dispatchEvent(evt);"
                +"}catch(e){}"
            );
            return true;
        case 20:
            webview.loadUrl("javascript: "
                +"try{"
                +"var evt = document.createEvent('Events');"
                +"evt.initEvent('keydown', true, true);"
                +"evt.keyCode = 40;"
                +"window.dispatchEvent(evt);"
                +"}catch(e){}"
            );
            return true;
        case 21:
            webview.loadUrl("javascript: "
                +"try{"
                +"var evt = document.createEvent('Events');"
                +"evt.initEvent('keydown', true, true);"
                +"evt.keyCode = 37;"
                +"window.dispatchEvent(evt);"
                +"}catch(e){}"
            );
            return true;
        case 22:
            webview.loadUrl("javascript: "
                +"try{"
                +"var evt = document.createEvent('Events');"
                +"evt.initEvent('keydown', true, true);"
                +"evt.keyCode = 39;"
                +"window.dispatchEvent(evt);"
                +"}catch(e){}"
            );
            return true;
        }
    }
    if (e.getAction() == KeyEvent.ACTION_DOWN) {
        switch(keyCode){
        case 19:
            webview.loadUrl("javascript: "
                +"try{"
                +"var evt = document.createEvent('Events');"
                +"evt.initEvent('keyup', true, true);"
                +"evt.keyCode = 38;"
                +"window.dispatchEvent(evt);"
                +"}catch(e){}"
            );
            return true;
        case 20:
            webview.loadUrl("javascript: "
                +"try{"
                +"var evt = document.createEvent('Events');"
                +"evt.initEvent('keyup', true, true);"
                +"evt.keyCode = 40;"
                +"window.dispatchEvent(evt);"
                +"}catch(e){}"
            );
            return true;
        case 21:
            webview.loadUrl("javascript: "
                +"try{"
                +"var evt = document.createEvent('Events');"
                +"evt.initEvent('keyup', true, true);"
                +"evt.keyCode = 37;"
                +"window.dispatchEvent(evt);"
                +"}catch(e){}"
            );
            return true;
        case 22:
            webview.loadUrl("javascript: "
                +"try{"
                +"var evt = document.createEvent('Events');"
                +"evt.initEvent('keyup', true, true);"
                +"evt.keyCode = 39;"
                +"window.dispatchEvent(evt);"
                +"}catch(e){}"
            );
            return true;
        }
    }
    return super.dispatchKeyEvent(e);
}

}



0 件のコメント:

コメントを投稿