[android][aznyan]NotePadをemacsライクな操作にしてみる

Posted October 9th, 2010 in General. Tagged: , , , .

ポイント

  • Ctrlキーの挙動について
    • aznyan特殊実装
      cf. [android][aznyan]キーコード(主にCtrlキー)を取得してみる – groundwalker.com
      http://groundwalker.com/blog/129
    • メタキーとして働く: getMetaState() == 0×8
  • IMEが処理する前に処理する
    • Ctl-AなどはIMEがキーイベントを消費して動作(全選択など)をしてしまうので、その前に奪い取る必要がある
    • EditText のサブクラスで dispatchKeyEventPreIme() を実装する
      cf. View.dispatchKeyEventPreIME()
      BACKキーもフックできるし(後述)
  • キーダウン時(KeyEvent.ACTION_DOWN)に処理する
  • キーイベントを模擬するには新しいKeyEventを生成して dispatchKeyEvent()に渡す。
    (これでいいのかわからないが動作は正常っぽい)
  • カーソル位置の制御には Selection を使う。選択にもこれ使うみたい
    cf. http://developer.android.com/reference/android/text/Selection.html

上記を踏まえて実装してみる

  • $androidsdk/samples/android-7/NotePad をコピーして
  • NoteEditor.java の NoteEditor.LinedEditTextクラス内に以下のコードを足す
    public static class LinedEditText extends EditText {
    	.....
    	@Override
    	public boolean dispatchKeyEventPreIme(KeyEvent e) {
    		// キーダウンで処理しないと色々やられちゃう
    		if (e.getAction() == KeyEvent.ACTION_DOWN) {
    			// CTRLキーは 0x8
    			if (e.getMetaState() == 0x8) {
    				// CTRLキーと一緒に押されたキーコードを得る
            		int code = e.getKeyCode();
            		// 新しいキーイベント生成用
                	KeyEvent ee = null;

                	switch(code) {
            		case KeyEvent.KEYCODE_F: // 右
            			// 以下のコードでも機能するけど、末尾エラー処理とか必要
            			// this.setSelection(mText.getSelectionStart()+1);
            			// なので、右矢印キーを模擬する、以下同様
            			ee = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_RIGHT);
            			break;
            		case KeyEvent.KEYCODE_B: // 左
            			ee = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_LEFT);
            			break;
            		case KeyEvent.KEYCODE_P: // 上
            			ee = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_UP);
            			break;
            		case KeyEvent.KEYCODE_N: // 下
            			ee = new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_DPAD_DOWN);
            			break;
            		case KeyEvent.KEYCODE_A: // 行頭
            			// なんかこんな感じでいけるらしい
            			Selection.moveToLeftEdge((Spannable)this.getText(), this.getLayout());
            			return true;
            		case KeyEvent.KEYCODE_E: // 行末
            			Selection.moveToRightEdge((Spannable)this.getText(), this.getLayout());
            			return true;
            		default:
            		}
            		if (ee != null) {
            			// 新しいキーイベントを作ってたら、処理させる
            			return dispatchKeyEvent(ee);
            		}
    			}
    		}
    		// 他の処理は親クラスに投げる
    		return super.dispatchKeyEventPreIme(e);
    	}
    	....
    }

無事動いたので後は。。

  • (全選択とかつぶしたのもあるし)選択系の操作を実装する
  • スクロール(Ctrl/Alt-v)
  • ほか、実装すると実用になるんじゃないかな
  • あと、実は Ctrl よりも CAPS LOCK 使いたいよね

参考:BACKボタン(バックボタン)のフックの仕方

...
    	@Override
    	public boolean dispatchKeyEventPreIme(KeyEvent e) {
    		// キーダウンをフックしないとだめ
    		if (e.getAction() == KeyEvent.ACTION_DOWN) {
        		int code = e.getKeyCode();
    			if (code == KeyEvent.KEYCODE_BACK) {
    				Toast.makeText(getContext(), "back pressed", Toast.LENGTH_SHORT).show();
    				// trueを返せばKeyEventを消費できる
    				return true;
    			}
        		...
    		}
    	}
    	...

関連情報

Posted October 9th, 2010 in General. Tagged: , , , .

One comment:

  1. BACKボタンのフックについてサンプルコードを追加した。

    groundwalker:

track feed