Android駆動の仮想キー


Android駆動の仮想キー
 
Published on 2010年03月22日
in android. 0 Comments
Tags: android, driver, kernel, linux, virualkey.
 
1背景
nexus one工業の設計は簡潔で、iphoneのボタンが1つしかないような設計で、真ん中のトラックボールしかありません.しかしandroid標準キーボードはHOME,MENU,BACK,SEARCHなどがあるが,同時に工業設計を維持しなければならない.nexus oneはこのように問題を解決し、ディスプレイは800 X 480であるが、容量タッチスクリーンが8 x*480であるところが800より大きいところが仮想ボタンとなり、android標準ボタンをシミュレートした.
 
2シナリオ
実装するには,仮想キーはandroidの中で2層の協力で実現され,下位層では仮想キーをディスプレイよりも多くの場所で仮想キーの位置サイズやキー値などを規定し,上位層にファイルインタフェースを与える.上位javaレイヤは、この領域のキー応答を読み出すサービスを開始します.これが概略的なアーキテクチャです.具体的には、次のようになります.
 
2.1最下位の仮想キー機能の実現方案は簡単に言えば、カーネルの中で仮想キーのすべての情報を上位に与えることであり、どのような方法で提供しますか?sysファイルシステムの方式で、sysファイルシステムの経路は約束したので、コードは以下のように実現します.情報を与えるプロトコルフォーマットは連続する文字列であり、各キーは6項目がそれぞれコロンで分割され、キー間もコロンで分割され、6項目は順にキータイプ:キー値:キー領域中心x座標:キー領域中心y座標:キー領域幅:キー領域高さarch/arm/mach-msm/board-mahimahiである.c  
 
 
static ssize_t mahimahi_virtual_keys_show(struct kobject *kobj,
			       struct kobj_attribute *attr, char *buf)
{
	if (system_rev > 2) {
		/* center: x: back: 55, menu: 172, home: 298, search 412, y: 835 */
		return sprintf(buf,
			__stringify(EV_KEY) ":" __stringify(KEY_BACK)  ":55:835:90:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU)   ":172:835:125:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME)   ":298:835:115:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":412:835:95:55"
		   "/n");
	} else {
		/* center: x: home: 55, menu: 185, back: 305, search 425, y: 835 */
		return sprintf(buf,
			__stringify(EV_KEY) ":" __stringify(KEY_HOME)  ":55:835:70:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU)   ":185:835:100:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK)   ":305:835:70:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":425:835:70:55"
		   "/n");
	}
}
 
static struct kobj_attribute mahimahi_virtual_keys_attr = {
	.attr = {
		.name = "virtualkeys.synaptics-rmi-touchscreen",
		.mode = S_IRUGO,
	},
	.show = &mahimahi_virtual_keys_show,
};
 
static struct attribute *mahimahi_properties_attrs[] = {
	&mahimahi_virtual_keys_attr.attr,
	NULL
};
 
static struct attribute_group mahimahi_properties_attr_group = {
	.attrs = mahimahi_properties_attrs,
};
 
struct kobject *properties_kobj;
 
properties_kobj = kobject_create_and_add("board_properties", NULL);
if (properties_kobj)
	ret = sysfs_create_group(properties_kobj,
					 &mahimahi_properties_attr_group);
if (!properties_kobj || ret)
	pr_err("failed to create board_properties/n");

 
JAVA上層案Java層は主にキー情報を読み取り、一定のアルゴリズムを経て、仮想キーを識別し、基本的に修正する必要はないが、java層のアーキテクチャを熟知することが望ましい.このような問題が発生した場合、frameworks/base/services/java/com/android/server/KeyInputQueueを位置決めするのに有利である.java  
 
/*これは仮想キーのクラスにVirtualKeyで使用されるメンバー変数とキーの位置決め方法が含まれています*/
    static class VirtualKey {
        int scancode;
        int centerx;
        int centery;
        int width;
        int height;
 
        int hitLeft;
        int hitTop;
        int hitRight;
        int hitBottom;
 
        InputDevice lastDevice;
        int lastKeycode;
 
        boolean checkHit(int x, int y) {
            return (x >= hitLeft && x <= hitRight                     && y >= hitTop && y <= hitBottom);
        }
 
        void computeHitRect(InputDevice dev, int dw, int dh) {
            if (dev == lastDevice) {
                return;
            }
            if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "computeHitRect for " + scancode
                    + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
 
            lastDevice = dev;
 
            int minx = dev.absX.minValue;
            int maxx = dev.absX.maxValue;
 
            int halfw = width/2;
            int left = centerx - halfw;
            int right = centerx + halfw;
            hitLeft = minx + ((left*maxx-minx)/dw);
            hitRight = minx + ((right*maxx-minx)/dw);
 
            int miny = dev.absY.minValue;
            int maxy = dev.absY.maxValue;
 
            int halfh = height/2;
            int top = centery - halfh;
            int bottom = centery + halfh;
            hitTop = miny + ((top*maxy-miny)/dh);
            hitBottom = miny + ((bottom*maxy-miny)/dh);
        }
    }
/*            ,             ,          ok*/
    private void readVirtualKeys(String deviceName) {
        try {
            FileInputStream fis = new FileInputStream(
                    "/sys/board_properties/virtualkeys." + deviceName);
/*      kernel       ,             ,             */
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader br = new BufferedReader(isr, 2048);
            String str = br.readLine();
            if (str != null) {
                String[] it = str.split(":");
                if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "***** VIRTUAL KEYS: " + it);
                final int N = it.length-6;
                for (int i=0; i<=N; i+=6) {
                    if (!"0x01".equals(it[i])) {
                        Log.w(TAG, "Unknown virtual key type at elem #" + i
                                + ": " + it[i]);
                        continue;
                    }
                    try {
                        VirtualKey sb = new VirtualKey();
                        sb.scancode = Integer.parseInt(it[i+1]);
                        sb.centerx = Integer.parseInt(it[i+2]);
                        sb.centery = Integer.parseInt(it[i+3]);
                        sb.width = Integer.parseInt(it[i+4]);
                        sb.height = Integer.parseInt(it[i+5]);
                        if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Virtual key "
                                + sb.scancode + ": center=" + sb.centerx + ","
                                + sb.centery + " size=" + sb.width + "x"
                                + sb.height);
                        mVirtualKeys.add(sb);
                    } catch (NumberFormatException e) {
                        Log.w(TAG, "Bad number at region " + i + " in: "
                                + str, e);
                    }
                }
            }
            br.close();
        } catch (FileNotFoundException e) {
            Log.i(TAG, "No virtual keys found");
        } catch (IOException e) {
            Log.w(TAG, "Error reading virtual keys", e);
        }
    }

基本的には、デバッグ作業に時間がかかる可能性があります.また、仮想キーを作るには、ハードウェアのサポート(表示領域を超えるタッチスクリーン領域)が必要です.このコードはandroid 2.1に基づいて実際の状況に応じて変更してください