Android keycode关联映射以及键值添加

文章目录

  • 前言
  • 一、系统中的keycode总览
  • 二、各keycode的关联对应
    • 1.kl文件中的keycode
    • 2.InputEventLabels.h中的KEYCODES[]
    • 3.keycodes.h定义了键值数字
    • 4.KeyEvent.java中的键值
    • 5./frameworks/base/core/res/res/values/attrs.xml中的键值
  • 总结


前言

Android的keycode添加需要在多个文件中进行键值增加,一个同样的键值在多个地方进行定义总是让人感觉不安的,所以下面我们通过走读代码重点看一下keycode对应关系,上层的keycode值如何对应到/dev/input/eventX中的上报值,为什么要在这些文件中定义,以及各个文件中的定义分别是做什么用的,到底以哪个为准。


一、系统中的keycode总览

系统中的keycode相关的定义的地方有(本文都以DPAD_CENTER为例,其他键值流程是一样的):

  1. kl文件中的keycode
key  0x4C  DPAD_CENTER
  1. /frameworks/native/include/input/InputEventLabels.h
DEFINE_KEYCODE(DPAD_CENTER),
  1. /frameworks/native/include/android/keycodes.h中
AKEYCODE_DPAD_CENTER     = 23,
  1. /frameworks/base/core/java/android/view/KeyEvent.java中
public static final int KEYCODE_DPAD_CENTER     = 23;
  1. /frameworks/base/core/res/res/values/attrs.xml
<enum name="KEYCODE_DPAD_CENTER" value="23" />

二、各keycode的关联对应

1.kl文件中的keycode

kl中定义了设备/dev/input/eventX中的上报值与系统键值的对应关系

key  0x4C  DPAD_CENTER

像这样的格式,即将设备上报的0x4C与DPAD_CENTER关联,过程是通过KeyLayoutMap.cpp的解析代码来实现的。

status_t KeyLayoutMap::Parser::parseKey() {
...
    //解析kl文件中event事件上报数值并赋值code,如0x4C
    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
...
    KeyedVector<int32_t, Key>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
...

    mTokenizer->skipDelimiters(WHITESPACE);
    //解析kl文件中的键值,如DPAD_CENTER
    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
    //通过DPAD_CENTER来获取系统中定义的键值
    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
...
    //保存到map
    Key key;
    key.keyCode = keyCode;
    key.flags = flags;
    map.add(code, key);
    return NO_ERROR;
}
  1. 在parseKey代码中首先解析event的上报值(这里为0x4C)。
  2. 然后解析键值字符串(DPAD_CENTER),通过getKeyCodeByLabel方法获取DPAD_CENTER在系统中定义的键值。
  3. 然后通过map.add(code, key);存入map,这样event的上报值和系统键值便有了对应关系。

2.InputEventLabels.h中的KEYCODES[]

前面提到了getKeyCodeByLabel方法,用于获取DPAD_CENTER在系统中定义的键值。

static inline int32_t getKeyCodeByLabel(const char* label) {
    return int32_t(lookupValueByLabel(label, KEYCODES));
}
static int lookupValueByLabel(const char* literal, const InputEventLabel *list) {
    while (list->literal) {
        if (strcmp(literal, list->literal) == 0) {
            return list->value;
        }
        list++;
    }
    return list->value;
}

可以看到getKeyCodeByLabel方法是通过KEYCODES来拿到键值数据的。

#define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }

struct InputEventLabel {
    const char *literal;
    int value;
};

static const InputEventLabel KEYCODES[] = {
    ...
    DEFINE_KEYCODE(DPAD_CENTER),
    ...
}

在InputEventLabels.h中KEYCODES是一个InputEventLabel 的数组,保存了所有的键值。通过DEFINE_KEYCODE宏,这里实际上可以理解为在KEYCODES中添加了

{DPAD_CENTER,AKEYCODE_DPAD_CENTER}。

这里DPAD_CENTER是一个字符串,AKEYCODE_DPAD_CENTER是一个int。getKeyCodeByLabel便能够通过遍历KEYCODES来拿到DPAD_CENTER对应的键值,也就是AKEYCODE_DPAD_CENTER。

3.keycodes.h定义了键值数字

键值数字的定义是在keycodes.h中,可以看到AKEYCODE_DPAD_CENTER的值是23。

/** Directional Pad Center key.
     * May also be synthesized from trackball motions. */
    AKEYCODE_DPAD_CENTER     = 23,

4.KeyEvent.java中的键值

keycodes.h中是定义了键值数据的,不过是在C++层。在Java层中也想要方便地使用keycode,因此在KeyEvent.java中也有一份键值的常量定义。
在KeyEvent.java中的键值常量是以KEYCODE_开头的。

/** Key code constant: Directional Pad Center key.
     * May also be synthesized from trackball motions. */
    public static final int KEYCODE_DPAD_CENTER     = 23;

KeyEvent.java中有常用的keyCodeToString和keyCodeFromString方法

    public static String keyCodeToString(int keyCode) {
        String symbolicName = nativeKeyCodeToString(keyCode);
        return symbolicName != null ? LABEL_PREFIX + symbolicName : Integer.toString(keyCode);
    }

keyCodeToString即是调用nativeKeyCodeToString来从InputEventLabels.h的KEYCODES中拿到对应的键值字符串,然后在前面加上"KEYCODE_"。

    public static int keyCodeFromString(@NonNull String symbolicName) {
        try {
            int keyCode = Integer.parseInt(symbolicName);
            if (keyCodeIsValid(keyCode)) {
                return keyCode;
            }
        } catch (NumberFormatException ex) {
        }

        if (symbolicName.startsWith(LABEL_PREFIX)) {
            symbolicName = symbolicName.substring(LABEL_PREFIX.length());
        }
        int keyCode = nativeKeyCodeFromString(symbolicName);
        if (keyCodeIsValid(keyCode)) {
            return keyCode;
        }
        return KEYCODE_UNKNOWN;
    }

keyCodeFromString也是类似,将KEYCODE_DPAD_CENTER去除前缀,然后从 KEYCODES中拿到对应键值。所以看到,键值的真正定义是在InputEventLabels.h和keycodes.h中的。

5./frameworks/base/core/res/res/values/attrs.xml中的键值

C层和Java层中都有了键值的常量定义,那attrs.xml的键值又是干什么的呢?

<attr name="keycode">
        <enum name="KEYCODE_UNKNOWN" value="0" />
        <enum name="KEYCODE_SOFT_LEFT" value="1" />
        <enum name="KEYCODE_SOFT_RIGHT" value="2" />
        <enum name="KEYCODE_HOME" value="3" />
        ...
attr>

attrs.xml的键值是为了在XML 布局文件中为相应的自定义 View 设置 keycode 属性

比如以下用法

<com.example.CustomView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:keycode="KEYCODE_SOFT_LEFT" />

public class CustomButton extends Button {
    private int keyCode;
    public CustomButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        
        // 从 XML 属性中获取 keycode 的值
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomButton);
        keyCode = typedArray.getInt(R.styleable.CustomButton_keycode, 0);
        typedArray.recycle();

        // 设置点击事件
        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // 根据 keycode 的值执行不同的操作
                switch (keyCode) {
                    case KeyEvent.KEYCODE_SOFT_LEFT:
                        // 执行 KEYCODE_SOFT_LEFT 对应的操作
                        break;
                    // 可以添加更多的 case 来处理其他键码
                    default:
                        // 默认操作
                        break;
                }
            }
        });
    }
}

不过目前在Android源码中搜索,使用这个keycode attr的基本没有。

总结

由以上可以看出

  • 键值的真实值的定义是在keycodes.h中,其他地方的值定义都应该以此为准。
  • InputEventLabels.h中include了keycodes.h,将键值的字符串关联了起来,并提供了查询方法。
  • Java层、kl文件都是通过InputEventLabels.h来进行键值的查询与匹配的。
  • attrs.xml是为了在XML
    布局文件中为相应的自定义 View 设置 keycode 属性,一般与KeyEvent.java中的键值进行对比使用。
    Android keycode关联映射以及键值添加_第1张图片

你可能感兴趣的:(Android,android)