IMS添加实体按键流程 - Android14

IMS添加实体按键流程 - Android14

  • 1、实体按键信息(Mi 9 左侧实体按键)
  • 2、硬件添加
    • 2.1 内核添加设备节点
    • 2.2 Generic.kl映射文件
    • 2.3 映射文件文件加载loadKeyMapLocked
    • 2.4 addDeviceLocked 添加设备相关对象
  • 3、keycode对应scankode
  • 4、KeyEvent.java 添加对应keycode

InputReader线程获取输入事件-Android12


1、实体按键信息(Mi 9 左侧实体按键)

  1. getevent 获取按键节点/dev/input/event3,scancode对应0x02b1 (即底层硬件上报的对应scancode)
  2. dumpsys input 获取对应按键映射文件KeyLayoutFile: /system/usr/keylayout/gpio-keys.klKeyCharacterMapFile: /system/usr/keychars/Generic.kcm,对应Sources: 0x00000101
    在这里插入图片描述

一般默认在 frameworks/base/data/keyboards/Generic.kl
mk配置文件:frameworks/base/data/keyboards/common.mkframeworks/base/data/keyboards/Android.mk

getevent

cepheus:/ $ getevent
add device 1: /dev/input/event7
  name:     "sm8150-tavil-snd-card USB_3_5 Jack"
add device 2: /dev/input/event6
  name:     "sm8150-tavil-snd-card Button Jack"
add device 3: /dev/input/event5
  name:     "sm8150-tavil-snd-card Headset Jack"
add device 4: /dev/input/event3
  name:     "gpio-keys"
add device 5: /dev/input/event2
  name:     "uinput-goodix"
add device 6: /dev/input/event0
  name:     "qpnp_pon"
add device 7: /dev/input/event1
  name:     "qti-haptics"
add device 8: /dev/input/event4
  name:     "fts"

/dev/input/event3: 0001 02b1 00000001
/dev/input/event3: 0000 0000 00000000
/dev/input/event3: 0001 02b1 00000000
/dev/input/event3: 0000 0000 00000000

/dev/input/event3: 0001 0073 00000001
/dev/input/event3: 0000 0000 00000000
/dev/input/event3: 0001 0073 00000000
/dev/input/event3: 0000 0000 00000000
/dev/input/event0: 0001 0072 00000001
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0001 0072 00000000
/dev/input/event0: 0000 0000 00000000

/dev/input/event0: 0001 0074 00000001
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0001 0074 00000000
/dev/input/event0: 0000 0000 00000000

adb shell dumpsys input > dumpsys_input.txt

    4: gpio-keys
      Classes: KEYBOARD
      Path: /dev/input/event3
      Enabled: true
      Descriptor: 485d69228e24f5e46da1598745890b214130dbc4
      Location: gpio-keys/input0
      ControllerNumber: 0
      UniqueId: 
      Identifier: bus=0x0019, vendor=0x0001, product=0x0001, version=0x0100
      KeyLayoutFile: /system/usr/keylayout/gpio-keys.kl
      KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
      ConfigurationFile: 
      VideoDevice: <none>


  Device 5: gpio-keys
    EventHub Devices: [ 4 ] 
    Generation: 15
    IsExternal: false
    AssociatedDisplayPort: <none>
    AssociatedDisplayUniqueId: <none>
    HasMic:     false
    Sources: 0x00000101
    KeyboardType: 1
    ControllerNum: 0
    Keyboard Input Mapper:
      Parameters:
        OrientationAware: false
        HandlesKeyRepeat: false
      KeyboardType: 1
      Orientation: 0
      KeyDowns: 0 keys currently down
      MetaState: 0x0
      DownTime: 0

2、硬件添加

2.1 内核添加设备节点

在Linux内核中提供了按键的驱动程序drivers/input/keyboard/gpio_keys.c解析,一般都是dts配置文件,scancode查看linux,code

  • POWER 按键:0074 /dev/input/event0: 0001 0074 00000001
  • 音量上下键:0073、0072 /dev/input/event3: 0001 0073 00000001 /dev/input/event0: 0001 0072 00000001
  • MI 9 左侧按键:02b1 /dev/input/event3: 0001 02b1 00000001
gpio-keys {
	compatible = "gpio-keys";
	input-name = "gpio-keys";

	pinctrl-names = "default";
	pinctrl-0 = <&gpio_keys_pin_a>;

	camera-snapshot {
		label = "camera_snapshot";
		gpios = <&pm8941_gpios 1 GPIO_ACTIVE_LOW>;
		linux,code = <KEY_CAMERA>;
		wakeup-source;
		debounce-interval = <15>;
	};

	volume-down {
		label = "volume_down";
		gpios = <&pm8941_gpios 2 GPIO_ACTIVE_LOW>;
		linux,code = <KEY_VOLUMEDOWN>;
		wakeup-source;
		debounce-interval = <15>;
	};

	volume-up {
		label = "volume_up";
		gpios = <&pm8941_gpios 5 GPIO_ACTIVE_LOW>;
		linux,code = <KEY_VOLUMEUP>;
		wakeup-source;
		debounce-interval = <15>;
	};
};

2.2 Generic.kl映射文件

系统提供了一个特殊的内置常规按键布局文件,名为 Generic.kl。此按键布局旨在支持各种标准外部键盘和操纵杆。请勿修改常规按键布局!

按键布局文件
按键字符映射文件
输入设备配置文件

2.3 映射文件文件加载loadKeyMapLocked

  • device->loadConfigurationLocked():这里导入kl配置文件,首先"Vendor_%04x_Product_%04x_Version_%04x%s",再次"Vendor_%04x_Product_%04x%s"。查看dumpsys input信息查看ConfigurationFile:一般为空。

  • loadKeyMapLocked 这里导入默认kl配置文件。这里左侧按键对应KeyLayoutFile: /system/usr/keylayout/gpio-keys.kl、power按键KeyLayoutFile: /system/usr/keylayout/Generic.kl
    在这里插入图片描述

frameworks/native/services/inputflinger/reader/EventHub.cpp

status_t EventHub::Device::loadKeyMapLocked() {
    return keyMap.load(identifier, configuration.get());
}

void EventHub::openDeviceLocked(const std::string& devicePath) {
    // If an input device happens to register around the time when EventHub's constructor runs, it
    // is possible that the same input event node (for example, /dev/input/event3) will be noticed
    // in both 'inotify' callback and also in the 'scanDirLocked' pass. To prevent duplicate devices
    // from getting registered, ensure that this path is not already covered by an existing device.
    for (const auto& [deviceId, device] : mDevices) {
        if (device->path == devicePath) {
            return; // device was already registered
        }
    }

    char buffer[80];

    ALOGV("Opening device: %s", devicePath.c_str());

    int fd = open(devicePath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
    if (fd < 0) {
        ALOGE("could not open %s, %s\n", devicePath.c_str(), strerror(errno));
        return;
    }

    InputDeviceIdentifier identifier;

    // Get device name.
    if (ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
        ALOGE("Could not get device name for %s: %s", devicePath.c_str(), strerror(errno));
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.name = buffer;
    }

    // Check to see if the device is on our excluded list
    for (size_t i = 0; i < mExcludedDevices.size(); i++) {
        const std::string& item = mExcludedDevices[i];
        if (identifier.name == item) {
            ALOGI("ignoring event id %s driver %s\n", devicePath.c_str(), item.c_str());
            close(fd);
            return;
        }
    }

    // Get device driver version.
    int driverVersion;
    if (ioctl(fd, EVIOCGVERSION, &driverVersion)) {
        ALOGE("could not get driver version for %s, %s\n", devicePath.c_str(), strerror(errno));
        close(fd);
        return;
    }

    // Get device identifier.
    struct input_id inputId;
    if (ioctl(fd, EVIOCGID, &inputId)) {
        ALOGE("could not get device input id for %s, %s\n", devicePath.c_str(), strerror(errno));
        close(fd);
        return;
    }
    identifier.bus = inputId.bustype;
    identifier.product = inputId.product;
    identifier.vendor = inputId.vendor;
    identifier.version = inputId.version;

    // Get device physical location.
    if (ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
        // fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.location = buffer;
    }

    // Get device unique id.
    if (ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
        // fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.uniqueId = buffer;
    }

    // Attempt to get the bluetooth address of an input device from the uniqueId.
    if (identifier.bus == BUS_BLUETOOTH &&
        std::regex_match(identifier.uniqueId,
                         std::regex("^[A-Fa-f0-9]{2}(?::[A-Fa-f0-9]{2}){5}$"))) {
        identifier.bluetoothAddress = identifier.uniqueId;
        // The Bluetooth stack requires alphabetic characters to be uppercase in a valid address.
        for (auto& c : *identifier.bluetoothAddress) {
            c = ::toupper(c);
        }
    }

    // Fill in the descriptor.
    assignDescriptorLocked(identifier);

    // Allocate device.  (The device object takes ownership of the fd at this point.)
    int32_t deviceId = mNextDeviceId++;
    std::unique_ptr<Device> device =
            std::make_unique<Device>(fd, deviceId, devicePath, identifier,
                                     obtainAssociatedDeviceLocked(devicePath));

    ALOGV("add device %d: %s\n", deviceId, devicePath.c_str());
    ALOGV("  bus:        %04x\n"
          "  vendor      %04x\n"
          "  product     %04x\n"
          "  version     %04x\n",
          identifier.bus, identifier.vendor, identifier.product, identifier.version);
    ALOGV("  name:       \"%s\"\n", identifier.name.c_str());
    ALOGV("  location:   \"%s\"\n", identifier.location.c_str());
    ALOGV("  unique id:  \"%s\"\n", identifier.uniqueId.c_str());
    ALOGV("  descriptor: \"%s\"\n", identifier.descriptor.c_str());
    ALOGV("  driver:     v%d.%d.%d\n", driverVersion >> 16, (driverVersion >> 8) & 0xff,
          driverVersion & 0xff);

    // Load the configuration file for the device.
    device->loadConfigurationLocked();

    // Figure out the kinds of events the device reports.
    device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0), device->keyBitmask);
    device->readDeviceBitMask(EVIOCGBIT(EV_ABS, 0), device->absBitmask);
    device->readDeviceBitMask(EVIOCGBIT(EV_REL, 0), device->relBitmask);
    device->readDeviceBitMask(EVIOCGBIT(EV_SW, 0), device->swBitmask);
    device->readDeviceBitMask(EVIOCGBIT(EV_LED, 0), device->ledBitmask);
    device->readDeviceBitMask(EVIOCGBIT(EV_FF, 0), device->ffBitmask);
    device->readDeviceBitMask(EVIOCGBIT(EV_MSC, 0), device->mscBitmask);
    device->readDeviceBitMask(EVIOCGPROP(0), device->propBitmask);

    // See if this is a device with keys. This could be full keyboard, or other devices like
    // gamepads, joysticks, and styluses with buttons that should generate key presses.
    bool haveKeyboardKeys =
            device->keyBitmask.any(0, BTN_MISC) || device->keyBitmask.any(BTN_WHEEL, KEY_MAX + 1);
    bool haveGamepadButtons = device->keyBitmask.any(BTN_MISC, BTN_MOUSE) ||
            device->keyBitmask.any(BTN_JOYSTICK, BTN_DIGI);
    bool haveStylusButtons = device->keyBitmask.test(BTN_STYLUS) ||
            device->keyBitmask.test(BTN_STYLUS2) || device->keyBitmask.test(BTN_STYLUS3);
    if (haveKeyboardKeys || haveGamepadButtons || haveStylusButtons) {
        device->classes |= InputDeviceClass::KEYBOARD;
    }

    // See if this is a cursor device such as a trackball or mouse.
    if (device->keyBitmask.test(BTN_MOUSE) && device->relBitmask.test(REL_X) &&
        device->relBitmask.test(REL_Y)) {
        device->classes |= InputDeviceClass::CURSOR;
    }

    // See if the device is specially configured to be of a certain type.
    if (device->configuration) {
        std::string deviceType = device->configuration->getString("device.type").value_or("");
        if (deviceType == "rotaryEncoder") {
            device->classes |= InputDeviceClass::ROTARY_ENCODER;
        } else if (deviceType == "externalStylus") {
            device->classes |= InputDeviceClass::EXTERNAL_STYLUS;
        }
    }

    // See if this is a touch pad.
    // Is this a new modern multi-touch driver?
    if (device->absBitmask.test(ABS_MT_POSITION_X) && device->absBitmask.test(ABS_MT_POSITION_Y)) {
        // Some joysticks such as the PS3 controller report axes that conflict
        // with the ABS_MT range.  Try to confirm that the device really is
        // a touch screen.
        if (device->keyBitmask.test(BTN_TOUCH) || !haveGamepadButtons) {
            device->classes |= (InputDeviceClass::TOUCH | InputDeviceClass::TOUCH_MT);
            if (device->propBitmask.test(INPUT_PROP_POINTER) &&
                !device->keyBitmask.any(BTN_TOOL_PEN, BTN_TOOL_FINGER) && !haveStylusButtons) {
                device->classes |= InputDeviceClass::TOUCHPAD;
            }
        }
        // Is this an old style single-touch driver?
    } else if (device->keyBitmask.test(BTN_TOUCH) && device->absBitmask.test(ABS_X) &&
               device->absBitmask.test(ABS_Y)) {
        device->classes |= InputDeviceClass::TOUCH;
        // Is this a stylus that reports contact/pressure independently of touch coordinates?
    } else if ((device->absBitmask.test(ABS_PRESSURE) || device->keyBitmask.test(BTN_TOUCH)) &&
               !device->absBitmask.test(ABS_X) && !device->absBitmask.test(ABS_Y)) {
        device->classes |= InputDeviceClass::EXTERNAL_STYLUS;
    }

    // See if this device is a joystick.
    // Assumes that joysticks always have gamepad buttons in order to distinguish them
    // from other devices such as accelerometers that also have absolute axes.
    if (haveGamepadButtons) {
        auto assumedClasses = device->classes | InputDeviceClass::JOYSTICK;
        for (int i = 0; i <= ABS_MAX; i++) {
            if (device->absBitmask.test(i) &&
                (getAbsAxisUsage(i, assumedClasses).test(InputDeviceClass::JOYSTICK))) {
                device->classes = assumedClasses;
                break;
            }
        }
    }

    // Check whether this device is an accelerometer.
    if (device->propBitmask.test(INPUT_PROP_ACCELEROMETER)) {
        device->classes |= InputDeviceClass::SENSOR;
    }

    // Check whether this device has switches.
    for (int i = 0; i <= SW_MAX; i++) {
        if (device->swBitmask.test(i)) {
            device->classes |= InputDeviceClass::SWITCH;
            break;
        }
    }

    // Check whether this device supports the vibrator.
    if (device->ffBitmask.test(FF_RUMBLE)) {
        device->classes |= InputDeviceClass::VIBRATOR;
    }

    // Configure virtual keys.
    if ((device->classes.test(InputDeviceClass::TOUCH))) {
        // Load the virtual keys for the touch screen, if any.
        // We do this now so that we can make sure to load the keymap if necessary.
        bool success = device->loadVirtualKeyMapLocked();
        if (success) {
            device->classes |= InputDeviceClass::KEYBOARD;
        }
    }

    // Load the key map.
    // We need to do this for joysticks too because the key layout may specify axes, and for
    // sensor as well because the key layout may specify the axes to sensor data mapping.
    status_t keyMapStatus = NAME_NOT_FOUND;
    if (device->classes.any(InputDeviceClass::KEYBOARD | InputDeviceClass::JOYSTICK |
                            InputDeviceClass::SENSOR)) {
        // Load the keymap for the device.
        keyMapStatus = device->loadKeyMapLocked();
    }

    // Configure the keyboard, gamepad or virtual keyboard.
    if (device->classes.test(InputDeviceClass::KEYBOARD)) {
        // Register the keyboard as a built-in keyboard if it is eligible.
        if (!keyMapStatus && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD &&
            isEligibleBuiltInKeyboard(device->identifier, device->configuration.get(),
                                      &device->keyMap)) {
            mBuiltInKeyboardId = device->id;
        }

        // 'Q' key support = cheap test of whether this is an alpha-capable kbd
        if (device->hasKeycodeLocked(AKEYCODE_Q)) {
            device->classes |= InputDeviceClass::ALPHAKEY;
        }

        // See if this device has a DPAD.
        if (device->hasKeycodeLocked(AKEYCODE_DPAD_UP) &&
            device->hasKeycodeLocked(AKEYCODE_DPAD_DOWN) &&
            device->hasKeycodeLocked(AKEYCODE_DPAD_LEFT) &&
            device->hasKeycodeLocked(AKEYCODE_DPAD_RIGHT) &&
            device->hasKeycodeLocked(AKEYCODE_DPAD_CENTER)) {
            device->classes |= InputDeviceClass::DPAD;
        }

        // See if this device has a gamepad.
        for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES) / sizeof(GAMEPAD_KEYCODES[0]); i++) {
            if (device->hasKeycodeLocked(GAMEPAD_KEYCODES[i])) {
                device->classes |= InputDeviceClass::GAMEPAD;
                break;
            }
        }

        // See if this device has any stylus buttons that we would want to fuse with touch data.
        if (!device->classes.any(InputDeviceClass::TOUCH | InputDeviceClass::TOUCH_MT)) {
            for (int32_t keycode : STYLUS_BUTTON_KEYCODES) {
                if (device->hasKeycodeLocked(keycode)) {
                    device->classes |= InputDeviceClass::EXTERNAL_STYLUS;
                    break;
                }
            }
        }
    }

    // If the device isn't recognized as something we handle, don't monitor it.
    if (device->classes == ftl::Flags<InputDeviceClass>(0)) {
        ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath.c_str(),
              device->identifier.name.c_str());
        return;
    }

    // Classify InputDeviceClass::BATTERY.
    if (device->associatedDevice && !device->associatedDevice->batteryInfos.empty()) {
        device->classes |= InputDeviceClass::BATTERY;
    }

    // Classify InputDeviceClass::LIGHT.
    if (device->associatedDevice && !device->associatedDevice->lightInfos.empty()) {
        device->classes |= InputDeviceClass::LIGHT;
    }

    // Determine whether the device has a mic.
    if (device->deviceHasMicLocked()) {
        device->classes |= InputDeviceClass::MIC;
    }

    // Determine whether the device is external or internal.
    if (device->isExternalDeviceLocked()) {
        device->classes |= InputDeviceClass::EXTERNAL;
    }

    if (device->classes.any(InputDeviceClass::JOYSTICK | InputDeviceClass::DPAD) &&
        device->classes.test(InputDeviceClass::GAMEPAD)) {
        device->controllerNumber = getNextControllerNumberLocked(device->identifier.name);
        device->setLedForControllerLocked();
    }

    if (registerDeviceForEpollLocked(*device) != OK) {
        return;
    }

    device->configureFd();

    ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=%s, "
          "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
          deviceId, fd, devicePath.c_str(), device->identifier.name.c_str(),
          device->classes.string().c_str(), device->configurationFile.c_str(),
          device->keyMap.keyLayoutFile.c_str(), device->keyMap.keyCharacterMapFile.c_str(),
          toString(mBuiltInKeyboardId == deviceId));

    addDeviceLocked(std::move(device));
}

frameworks/native/libs/input/Keyboard.cpp

static std::string getPath(const InputDeviceIdentifier& deviceIdentifier, const std::string& name,
                           InputDeviceConfigurationFileType type) {
    return name.empty()
            ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
            : getInputDeviceConfigurationFilePathByName(name, type);
}

status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier,
        const PropertyMap* deviceConfiguration) {
    // Use the configured key layout if available.
    if (deviceConfiguration) {
        std::optional<std::string> keyLayoutName =
                deviceConfiguration->getString("keyboard.layout");
        if (keyLayoutName.has_value()) {
            status_t status = loadKeyLayout(deviceIdentifier, *keyLayoutName);
            if (status == NAME_NOT_FOUND) {
                ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
                      "it was not found.",
                      deviceIdentifier.name.c_str(), keyLayoutName->c_str());
            }
        }

        std::optional<std::string> keyCharacterMapName =
                deviceConfiguration->getString("keyboard.characterMap");
        if (keyCharacterMapName.has_value()) {
            status_t status = loadKeyCharacterMap(deviceIdentifier, *keyCharacterMapName);
            if (status == NAME_NOT_FOUND) {
                ALOGE("Configuration for keyboard device '%s' requested keyboard character "
                      "map '%s' but it was not found.",
                      deviceIdentifier.name.c_str(), keyCharacterMapName->c_str());
            }
        }

        if (isComplete()) {
            return OK;
        }
    }

    // Try searching by device identifier.
    if (probeKeyMap(deviceIdentifier, "")) {
        return OK;
    }

    // Fall back on the Generic key map.
    // TODO Apply some additional heuristics here to figure out what kind of
    //      generic key map to use (US English, etc.) for typical external keyboards.
    if (probeKeyMap(deviceIdentifier, "Generic")) {
        return OK;
    }

    // Try the Virtual key map as a last resort.
    if (probeKeyMap(deviceIdentifier, "Virtual")) {
        return OK;
    }

    // Give up!
    ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
            deviceIdentifier.name.c_str());
    return NAME_NOT_FOUND;
}

bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
        const std::string& keyMapName) {
    if (!haveKeyLayout()) {
        loadKeyLayout(deviceIdentifier, keyMapName);
    }
    if (!haveKeyCharacterMap()) {
        loadKeyCharacterMap(deviceIdentifier, keyMapName);
    }
    return isComplete();
}

status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
        const std::string& name) {
    std::string path(getPath(deviceIdentifier, name, InputDeviceConfigurationFileType::KEY_LAYOUT));
    if (path.empty()) {
        return NAME_NOT_FOUND;
    }

    base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(path);
    if (ret.ok()) {
        keyLayoutMap = *ret;
        keyLayoutFile = path;
        return OK;
    }

    // Try to load fallback layout if the regular layout could not be loaded due to missing
    // kernel modules
    std::string fallbackPath(
            getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier,
                                                                  InputDeviceConfigurationFileType::
                                                                          KEY_LAYOUT,
                                                                  "_fallback"));
    ret = KeyLayoutMap::load(fallbackPath);
    if (!ret.ok()) {
        return ret.error().code();
    }
    keyLayoutMap = *ret;
    keyLayoutFile = fallbackPath;
    return OK;
}

frameworks/native/libs/input/InputDevice.cpp

std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
        const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type,
        const char* suffix) {
    if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
        if (deviceIdentifier.version != 0) {
            // Try vendor product version.
            std::string versionPath =
                    getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%"
                                                                           "04x_Version_%04x%s",
                                                                           deviceIdentifier.vendor,
                                                                           deviceIdentifier.product,
                                                                           deviceIdentifier.version,
                                                                           suffix),
                                                              type);
            if (!versionPath.empty()) {
                return versionPath;
            }
        }

        // Try vendor product.
        std::string productPath =
                getInputDeviceConfigurationFilePathByName(StringPrintf("Vendor_%04x_Product_%04x%s",
                                                                       deviceIdentifier.vendor,
                                                                       deviceIdentifier.product,
                                                                       suffix),
                                                          type);
        if (!productPath.empty()) {
            return productPath;
        }
    }

    // Try device name.
    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName() + suffix,
                                                     type);
}

std::string getInputDeviceConfigurationFilePathByName(
        const std::string& name, InputDeviceConfigurationFileType type) {
    // Search system repository.
    std::string path;

    // Treblized input device config files will be located /product/usr, /system_ext/usr,
    // /odm/usr or /vendor/usr.
    // These files may also be in the com.android.input.config APEX.
    const char* rootsForPartition[]{
            "/product",
            "/system_ext",
            "/odm",
            "/vendor",
            "/apex/com.android.input.config/etc",
            getenv("ANDROID_ROOT"),
    };
    for (size_t i = 0; i < size(rootsForPartition); i++) {
        if (rootsForPartition[i] == nullptr) {
            continue;
        }
        path = rootsForPartition[i];
        path += "/usr/";
        appendInputDeviceConfigurationFileRelativePath(path, name, type);
#if DEBUG_PROBE
        ALOGD("Probing for system provided input device configuration file: path='%s'",
              path.c_str());
#endif
        if (!access(path.c_str(), R_OK)) {
#if DEBUG_PROBE
            ALOGD("Found");
#endif
            return path;
        }
    }

    // Search user repository.
    // TODO Should only look here if not in safe mode.
    path = "";
    char *androidData = getenv("ANDROID_DATA");
    if (androidData != nullptr) {
        path += androidData;
    }
    path += "/system/devices/";
    appendInputDeviceConfigurationFileRelativePath(path, name, type);
#if DEBUG_PROBE
    ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str());
#endif
    if (!access(path.c_str(), R_OK)) {
#if DEBUG_PROBE
        ALOGD("Found");
#endif
        return path;
    }

    // Not found.
#if DEBUG_PROBE
    ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
            name.c_str(), type);
#endif
    return "";
}

2.4 addDeviceLocked 添加设备相关对象

addDeviceLocked 添加设备、IMS:EventHub 设备添加和InputDevice转化 其中EventHub::scanDevicesLocked()查询DEVICE_INPUT_PATH = "/dev/input"路径添加/dev/input/event3

  • InputDeviceIdentifier
  • Device
  • InputDevice
  • InputMapper: frameworks/native/services/inputflinger/reader/mapperClasses: KEYBOARD / Sources: 0x00000101 这里对应KeyboardInputMapper.cppAINPUT_SOURCE_KEYBOARD = 0x00000100 | AINPUT_SOURCE_CLASS_BUTTON
  • InputDeviceInfo

frameworks/native/services/inputflinger/reader/InputReader.cpp

void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
    if (mDevices.find(eventHubId) != mDevices.end()) {
        ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);
        return;
    }

    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
    std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);

    notifyAll(device->configure(when, mConfig, /*changes=*/{}));
    notifyAll(device->reset(when));

    if (device->isIgnored()) {
        ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s' "
              "(ignored non-input device)",
              device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str());
    } else {
        ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s',sources=%s",
              device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str(),
              inputEventSourceToString(device->getSources()).c_str());
    }

    mDevices.emplace(eventHubId, device);
    // Add device to device to EventHub ids map.
    const auto mapIt = mDeviceToEventHubIdsMap.find(device);
    if (mapIt == mDeviceToEventHubIdsMap.end()) {
        std::vector<int32_t> ids = {eventHubId};
        mDeviceToEventHubIdsMap.emplace(device, ids);
    } else {
        mapIt->second.push_back(eventHubId);
    }
    bumpGenerationLocked();

    if (device->getClasses().test(InputDeviceClass::EXTERNAL_STYLUS)) {
        notifyExternalStylusPresenceChangedLocked();
    }

    // Sensor input device is noisy, to save power disable it by default.
    // Input device is classified as SENSOR when any sub device is a SENSOR device, check Eventhub
    // device class to disable SENSOR sub device only.
    if (mEventHub->getDeviceClasses(eventHubId).test(InputDeviceClass::SENSOR)) {
        mEventHub->disableDevice(eventHubId);
    }
}

std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
        int32_t eventHubId, const InputDeviceIdentifier& identifier) {
    auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {
        const InputDeviceIdentifier identifier2 =
                devicePair.second->getDeviceInfo().getIdentifier();
        return isSubDevice(identifier, identifier2);
    });

    std::shared_ptr<InputDevice> device;
    if (deviceIt != mDevices.end()) {
        device = deviceIt->second;
    } else {
        int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();
        device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
                                               identifier);
    }
    device->addEventHubDevice(eventHubId, mConfig);
    return device;
}

frameworks/native/services/inputflinger/reader/InputDevice.cpp

InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
                         const InputDeviceIdentifier& identifier)
      : mContext(context),
        mId(id),
        mGeneration(generation),
        mControllerNumber(0),
        mIdentifier(identifier),
        mClasses(0),
        mSources(0),
        mIsExternal(false),
        mHasMic(false),
        mDropUntilNextSync(false) {}


void InputDevice::addEventHubDevice(int32_t eventHubId,
                                    const InputReaderConfiguration& readerConfig) {
    if (mDevices.find(eventHubId) != mDevices.end()) {
        return;
    }
    std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
    std::vector<std::unique_ptr<InputMapper>> mappers = createMappers(*contextPtr, readerConfig);

    // insert the context into the devices set
    mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
    // Must change generation to flag this device as changed
    bumpGeneration();
}


std::vector<std::unique_ptr<InputMapper>> InputDevice::createMappers(
        InputDeviceContext& contextPtr, const InputReaderConfiguration& readerConfig) {
    ftl::Flags<InputDeviceClass> classes = contextPtr.getDeviceClasses();
    std::vector<std::unique_ptr<InputMapper>> mappers;

    // Switch-like devices.
    if (classes.test(InputDeviceClass::SWITCH)) {
        mappers.push_back(createInputMapper<SwitchInputMapper>(contextPtr, readerConfig));
    }

    // Scroll wheel-like devices.
    if (classes.test(InputDeviceClass::ROTARY_ENCODER)) {
        mappers.push_back(createInputMapper<RotaryEncoderInputMapper>(contextPtr, readerConfig));
    }

    // Vibrator-like devices.
    if (classes.test(InputDeviceClass::VIBRATOR)) {
        mappers.push_back(createInputMapper<VibratorInputMapper>(contextPtr, readerConfig));
    }

    // Battery-like devices or light-containing devices.
    // PeripheralController will be created with associated EventHub device.
    if (classes.test(InputDeviceClass::BATTERY) || classes.test(InputDeviceClass::LIGHT)) {
        mController = std::make_unique<PeripheralController>(contextPtr);
    }

    // Keyboard-like devices.
    uint32_t keyboardSource = 0;
    int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
    if (classes.test(InputDeviceClass::KEYBOARD)) {
        keyboardSource |= AINPUT_SOURCE_KEYBOARD;
    }
    if (classes.test(InputDeviceClass::ALPHAKEY)) {
        keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
    }
    if (classes.test(InputDeviceClass::DPAD)) {
        keyboardSource |= AINPUT_SOURCE_DPAD;
    }
    if (classes.test(InputDeviceClass::GAMEPAD)) {
        keyboardSource |= AINPUT_SOURCE_GAMEPAD;
    }

    if (keyboardSource != 0) {
        mappers.push_back(createInputMapper<KeyboardInputMapper>(contextPtr, readerConfig,
                                                                 keyboardSource, keyboardType));
    }

    // Cursor-like devices.
    if (classes.test(InputDeviceClass::CURSOR)) {
        mappers.push_back(createInputMapper<CursorInputMapper>(contextPtr, readerConfig));
    }

    // Touchscreens and touchpad devices.
    static const bool ENABLE_TOUCHPAD_GESTURES_LIBRARY =
            sysprop::InputProperties::enable_touchpad_gestures_library().value_or(true);
    // TODO(b/272518665): Fix the new touchpad stack for Sony DualShock 4 (5c4, 9cc) touchpads, or
    // at least load this setting from the IDC file.
    const InputDeviceIdentifier identifier = contextPtr.getDeviceIdentifier();
    const bool isSonyDualShock4Touchpad = identifier.vendor == 0x054c &&
            (identifier.product == 0x05c4 || identifier.product == 0x09cc);
    if (ENABLE_TOUCHPAD_GESTURES_LIBRARY && classes.test(InputDeviceClass::TOUCHPAD) &&
        classes.test(InputDeviceClass::TOUCH_MT) && !isSonyDualShock4Touchpad) {
        mappers.push_back(createInputMapper<TouchpadInputMapper>(contextPtr, readerConfig));
    } else if (classes.test(InputDeviceClass::TOUCH_MT)) {
        mappers.push_back(std::make_unique<MultiTouchInputMapper>(contextPtr, readerConfig));
    } else if (classes.test(InputDeviceClass::TOUCH)) {
        mappers.push_back(std::make_unique<SingleTouchInputMapper>(contextPtr, readerConfig));
    }

    // Joystick-like devices.
    if (classes.test(InputDeviceClass::JOYSTICK)) {
        mappers.push_back(createInputMapper<JoystickInputMapper>(contextPtr, readerConfig));
    }

    // Motion sensor enabled devices.
    if (classes.test(InputDeviceClass::SENSOR)) {
        mappers.push_back(createInputMapper<SensorInputMapper>(contextPtr, readerConfig));
    }

    // External stylus-like devices.
    if (classes.test(InputDeviceClass::EXTERNAL_STYLUS)) {
        mappers.push_back(createInputMapper<ExternalStylusInputMapper>(contextPtr, readerConfig));
    }
    return mappers;
}

void InputDevice::addEventHubDevice(int32_t eventHubId,
                                    const InputReaderConfiguration& readerConfig) {
    if (mDevices.find(eventHubId) != mDevices.end()) {
        return;
    }
    std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
    std::vector<std::unique_ptr<InputMapper>> mappers = createMappers(*contextPtr, readerConfig);

    // insert the context into the devices set
    mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
    // Must change generation to flag this device as changed
    bumpGeneration();
}

frameworks/native/include/input/InputDevice.h

inline uint32_t getSources() const { return mSources; }

frameworks/native/libs/input/InputDevice.cpp

void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
                                 const InputDeviceIdentifier& identifier, const std::string& alias,
                                 bool isExternal, bool hasMic, int32_t associatedDisplayId) {
    mId = id;
    mGeneration = generation;
    mControllerNumber = controllerNumber;
    mIdentifier = identifier;
    mAlias = alias;
    mIsExternal = isExternal;
    mHasMic = hasMic;
    mSources = 0;
    mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
    mAssociatedDisplayId = associatedDisplayId;
    mHasVibrator = false;
    mHasBattery = false;
    mHasButtonUnderPad = false;
    mHasSensor = false;
    mUsiVersion.reset();
    mMotionRanges.clear();
    mSensors.clear();
    mLights.clear();
}

void InputDeviceInfo::addSource(uint32_t source) {
    mSources |= source;
}

3、keycode对应scankode

2.3 映射文件文件加载loadKeyMapLocked加载 KeyLayoutMap::load(path) 时对应转换,对照kl文件解析,如POWER按键

key 114   VOLUME_DOWN
key 115   VOLUME_UP
key 116   POWER
  • keywordToken == "key":kl文件每行开头关键字key
  • parseKey() -> code = parseInt(codeToken.string()): kl文件关键字key之后的116,对应底层上报的scancode
  • keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()):kl文件关键字key之后最后的关键字POWER转换keycode
  • DEFINE_KEYCODE(POWER):对应到 AKEYCODE_POWER = 26

frameworks/native/libs/input/KeyLayoutMap.cpp

status_t KeyLayoutMap::Parser::parse() {
    while (!mTokenizer->isEof()) {
        ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(),
                 mTokenizer->peekRemainderOfLine().string());

        mTokenizer->skipDelimiters(WHITESPACE);

        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
            String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
            if (keywordToken == "key") {
                mTokenizer->skipDelimiters(WHITESPACE);
                status_t status = parseKey();
                if (status) return status;
            } else if (keywordToken == "axis") {
                mTokenizer->skipDelimiters(WHITESPACE);
                status_t status = parseAxis();
                if (status) return status;
            } else if (keywordToken == "led") {
                mTokenizer->skipDelimiters(WHITESPACE);
                status_t status = parseLed();
                if (status) return status;
            } else if (keywordToken == "sensor") {
                mTokenizer->skipDelimiters(WHITESPACE);
                status_t status = parseSensor();
                if (status) return status;
            } else if (keywordToken == "requires_kernel_config") {
                mTokenizer->skipDelimiters(WHITESPACE);
                status_t status = parseRequiredKernelConfig();
                if (status) return status;
            } else {
                ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
                        keywordToken.string());
                return BAD_VALUE;
            }

            mTokenizer->skipDelimiters(WHITESPACE);
            if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
                ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
                        mTokenizer->getLocation().string(),
                        mTokenizer->peekRemainderOfLine().string());
                return BAD_VALUE;
            }
        }

        mTokenizer->nextLine();
    }
    return NO_ERROR;
}

status_t KeyLayoutMap::Parser::parseKey() {
    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
    bool mapUsage = false;
    if (codeToken == "usage") {
        mapUsage = true;
        mTokenizer->skipDelimiters(WHITESPACE);
        codeToken = mTokenizer->nextToken(WHITESPACE);
    }

    std::optional<int> code = parseInt(codeToken.string());
    if (!code) {
        ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
                mapUsage ? "usage" : "scan code", codeToken.string());
        return BAD_VALUE;
    }
    std::unordered_map<int32_t, Key>& map =
            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
    if (map.find(*code) != map.end()) {
        ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
                mapUsage ? "usage" : "scan code", codeToken.string());
        return BAD_VALUE;
    }

    mTokenizer->skipDelimiters(WHITESPACE);
    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
    std::optional<int> keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string());
    if (!keyCode) {
        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
                keyCodeToken.string());
        return BAD_VALUE;
    }

    uint32_t flags = 0;
    for (;;) {
        mTokenizer->skipDelimiters(WHITESPACE);
        if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;

        String8 flagToken = mTokenizer->nextToken(WHITESPACE);
        std::optional<int> flag = InputEventLookup::getKeyFlagByLabel(flagToken.string());
        if (!flag) {
            ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
                    flagToken.string());
            return BAD_VALUE;
        }
        if (flags & *flag) {
            ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
                    flagToken.string());
            return BAD_VALUE;
        }
        flags |= *flag;
    }

    ALOGD_IF(DEBUG_PARSER, "Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
             mapUsage ? "usage" : "scan code", *code, *keyCode, flags);

    Key key;
    key.keyCode = *keyCode;
    key.flags = flags;
    map.insert({*code, key});
    return NO_ERROR;
}

bionic/libc/kernel/uapi/linux/input-event-codes.h
frameworks/native/libs/input/InputEventLabels.cpp

#define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }
// NOTE: If you add a new keycode here you must also add it to several other files.
//       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
#define KEYCODES_SEQUENCE \
    DEFINE_KEYCODE(UNKNOWN), \
    DEFINE_KEYCODE(SOFT_LEFT), \
    DEFINE_KEYCODE(SOFT_RIGHT), \
    DEFINE_KEYCODE(HOME), \
    DEFINE_KEYCODE(BACK), \
    DEFINE_KEYCODE(CALL), \
    DEFINE_KEYCODE(ENDCALL), \
    DEFINE_KEYCODE(0), \
    DEFINE_KEYCODE(1), \
    DEFINE_KEYCODE(2), \
    DEFINE_KEYCODE(3), \
    DEFINE_KEYCODE(4), \
    DEFINE_KEYCODE(5), \
    DEFINE_KEYCODE(6), \
    DEFINE_KEYCODE(7), \
    DEFINE_KEYCODE(8), \
    DEFINE_KEYCODE(9), \
    DEFINE_KEYCODE(STAR), \
    DEFINE_KEYCODE(POUND), \
    DEFINE_KEYCODE(DPAD_UP), \
    DEFINE_KEYCODE(DPAD_DOWN), \
    DEFINE_KEYCODE(DPAD_LEFT), \
    DEFINE_KEYCODE(DPAD_RIGHT), \
    DEFINE_KEYCODE(DPAD_CENTER), \
    DEFINE_KEYCODE(VOLUME_UP), \
    DEFINE_KEYCODE(VOLUME_DOWN), \
    DEFINE_KEYCODE(POWER), \
    DEFINE_KEYCODE(CAMERA), \
    DEFINE_KEYCODE(CLEAR), \
    DEFINE_KEYCODE(A), \
    DEFINE_KEYCODE(B), \
    DEFINE_KEYCODE(C), \
    DEFINE_KEYCODE(D), \
    DEFINE_KEYCODE(E), \
    DEFINE_KEYCODE(F), \
    DEFINE_KEYCODE(G), \
    DEFINE_KEYCODE(H), \
    DEFINE_KEYCODE(I), \
    DEFINE_KEYCODE(J), \
    DEFINE_KEYCODE(K), \
    DEFINE_KEYCODE(L), \
    DEFINE_KEYCODE(M), \
    DEFINE_KEYCODE(N), \
    DEFINE_KEYCODE(O), \
    DEFINE_KEYCODE(P), \
    DEFINE_KEYCODE(Q), \
    DEFINE_KEYCODE(R), \
    DEFINE_KEYCODE(S), \
    DEFINE_KEYCODE(T), \
    DEFINE_KEYCODE(U), \
    DEFINE_KEYCODE(V), \
    DEFINE_KEYCODE(W), \
    DEFINE_KEYCODE(X), \
    DEFINE_KEYCODE(Y), \
    DEFINE_KEYCODE(Z), \
    DEFINE_KEYCODE(COMMA), \
    DEFINE_KEYCODE(PERIOD), \
    DEFINE_KEYCODE(ALT_LEFT), \
    DEFINE_KEYCODE(ALT_RIGHT), \
    DEFINE_KEYCODE(SHIFT_LEFT), \
    DEFINE_KEYCODE(SHIFT_RIGHT), \
    DEFINE_KEYCODE(TAB), \
    DEFINE_KEYCODE(SPACE), \
    DEFINE_KEYCODE(SYM), \
    DEFINE_KEYCODE(EXPLORER), \
    DEFINE_KEYCODE(ENVELOPE), \
    DEFINE_KEYCODE(ENTER), \
    DEFINE_KEYCODE(DEL), \
    DEFINE_KEYCODE(GRAVE), \
    DEFINE_KEYCODE(MINUS), \
    DEFINE_KEYCODE(EQUALS), \
    DEFINE_KEYCODE(LEFT_BRACKET), \
    DEFINE_KEYCODE(RIGHT_BRACKET), \
    DEFINE_KEYCODE(BACKSLASH), \
    DEFINE_KEYCODE(SEMICOLON), \
    DEFINE_KEYCODE(APOSTROPHE), \
    DEFINE_KEYCODE(SLASH), \
    DEFINE_KEYCODE(AT), \
    DEFINE_KEYCODE(NUM), \
    DEFINE_KEYCODE(HEADSETHOOK), \
    DEFINE_KEYCODE(FOCUS), \
    DEFINE_KEYCODE(PLUS), \
    DEFINE_KEYCODE(MENU), \
    DEFINE_KEYCODE(NOTIFICATION), \
    DEFINE_KEYCODE(SEARCH), \
    DEFINE_KEYCODE(MEDIA_PLAY_PAUSE), \
    DEFINE_KEYCODE(MEDIA_STOP), \
    DEFINE_KEYCODE(MEDIA_NEXT), \
    DEFINE_KEYCODE(MEDIA_PREVIOUS), \
    DEFINE_KEYCODE(MEDIA_REWIND), \
    DEFINE_KEYCODE(MEDIA_FAST_FORWARD), \
    DEFINE_KEYCODE(MUTE), \
    DEFINE_KEYCODE(PAGE_UP), \
    DEFINE_KEYCODE(PAGE_DOWN), \
    DEFINE_KEYCODE(PICTSYMBOLS), \
    DEFINE_KEYCODE(SWITCH_CHARSET), \
    DEFINE_KEYCODE(BUTTON_A), \
    DEFINE_KEYCODE(BUTTON_B), \
    DEFINE_KEYCODE(BUTTON_C), \
    DEFINE_KEYCODE(BUTTON_X), \
    DEFINE_KEYCODE(BUTTON_Y), \
    DEFINE_KEYCODE(BUTTON_Z), \
    DEFINE_KEYCODE(BUTTON_L1), \
    DEFINE_KEYCODE(BUTTON_R1), \
    DEFINE_KEYCODE(BUTTON_L2), \
    DEFINE_KEYCODE(BUTTON_R2), \
    DEFINE_KEYCODE(BUTTON_THUMBL), \
    DEFINE_KEYCODE(BUTTON_THUMBR), \
    DEFINE_KEYCODE(BUTTON_START), \
    DEFINE_KEYCODE(BUTTON_SELECT), \
    DEFINE_KEYCODE(BUTTON_MODE), \
    DEFINE_KEYCODE(ESCAPE), \
    DEFINE_KEYCODE(FORWARD_DEL), \
    DEFINE_KEYCODE(CTRL_LEFT), \
    DEFINE_KEYCODE(CTRL_RIGHT), \
    DEFINE_KEYCODE(CAPS_LOCK), \
    DEFINE_KEYCODE(SCROLL_LOCK), \
    DEFINE_KEYCODE(META_LEFT), \
    DEFINE_KEYCODE(META_RIGHT), \
    DEFINE_KEYCODE(FUNCTION), \
    DEFINE_KEYCODE(SYSRQ), \
    DEFINE_KEYCODE(BREAK), \
    DEFINE_KEYCODE(MOVE_HOME), \
    DEFINE_KEYCODE(MOVE_END), \
    DEFINE_KEYCODE(INSERT), \
    DEFINE_KEYCODE(FORWARD), \
    DEFINE_KEYCODE(MEDIA_PLAY), \
    DEFINE_KEYCODE(MEDIA_PAUSE), \
    DEFINE_KEYCODE(MEDIA_CLOSE), \
    DEFINE_KEYCODE(MEDIA_EJECT), \
    DEFINE_KEYCODE(MEDIA_RECORD), \
    DEFINE_KEYCODE(F1), \
    DEFINE_KEYCODE(F2), \
    DEFINE_KEYCODE(F3), \
    DEFINE_KEYCODE(F4), \
    DEFINE_KEYCODE(F5), \
    DEFINE_KEYCODE(F6), \
    DEFINE_KEYCODE(F7), \
    DEFINE_KEYCODE(F8), \
    DEFINE_KEYCODE(F9), \
    DEFINE_KEYCODE(F10), \
    DEFINE_KEYCODE(F11), \
    DEFINE_KEYCODE(F12), \
    DEFINE_KEYCODE(NUM_LOCK), \
    DEFINE_KEYCODE(NUMPAD_0), \
    DEFINE_KEYCODE(NUMPAD_1), \
    DEFINE_KEYCODE(NUMPAD_2), \
    DEFINE_KEYCODE(NUMPAD_3), \
    DEFINE_KEYCODE(NUMPAD_4), \
    DEFINE_KEYCODE(NUMPAD_5), \
    DEFINE_KEYCODE(NUMPAD_6), \
    DEFINE_KEYCODE(NUMPAD_7), \
    DEFINE_KEYCODE(NUMPAD_8), \
    DEFINE_KEYCODE(NUMPAD_9), \
    DEFINE_KEYCODE(NUMPAD_DIVIDE), \
    DEFINE_KEYCODE(NUMPAD_MULTIPLY), \
    DEFINE_KEYCODE(NUMPAD_SUBTRACT), \
    DEFINE_KEYCODE(NUMPAD_ADD), \
    DEFINE_KEYCODE(NUMPAD_DOT), \
    DEFINE_KEYCODE(NUMPAD_COMMA), \
    DEFINE_KEYCODE(NUMPAD_ENTER), \
    DEFINE_KEYCODE(NUMPAD_EQUALS), \
    DEFINE_KEYCODE(NUMPAD_LEFT_PAREN), \
    DEFINE_KEYCODE(NUMPAD_RIGHT_PAREN), \
    DEFINE_KEYCODE(VOLUME_MUTE), \
    DEFINE_KEYCODE(INFO), \
    DEFINE_KEYCODE(CHANNEL_UP), \
    DEFINE_KEYCODE(CHANNEL_DOWN), \
    DEFINE_KEYCODE(ZOOM_IN), \
    DEFINE_KEYCODE(ZOOM_OUT), \
    DEFINE_KEYCODE(TV), \
    DEFINE_KEYCODE(WINDOW), \
    DEFINE_KEYCODE(GUIDE), \
    DEFINE_KEYCODE(DVR), \
    DEFINE_KEYCODE(BOOKMARK), \
    DEFINE_KEYCODE(CAPTIONS), \
    DEFINE_KEYCODE(SETTINGS), \
    DEFINE_KEYCODE(TV_POWER), \
    DEFINE_KEYCODE(TV_INPUT), \
    DEFINE_KEYCODE(STB_POWER), \
    DEFINE_KEYCODE(STB_INPUT), \
    DEFINE_KEYCODE(AVR_POWER), \
    DEFINE_KEYCODE(AVR_INPUT), \
    DEFINE_KEYCODE(PROG_RED), \
    DEFINE_KEYCODE(PROG_GREEN), \
    DEFINE_KEYCODE(PROG_YELLOW), \
    DEFINE_KEYCODE(PROG_BLUE), \
    DEFINE_KEYCODE(APP_SWITCH), \
    DEFINE_KEYCODE(BUTTON_1), \
    DEFINE_KEYCODE(BUTTON_2), \
    DEFINE_KEYCODE(BUTTON_3), \
    DEFINE_KEYCODE(BUTTON_4), \
    DEFINE_KEYCODE(BUTTON_5), \
    DEFINE_KEYCODE(BUTTON_6), \
    DEFINE_KEYCODE(BUTTON_7), \
    DEFINE_KEYCODE(BUTTON_8), \
    DEFINE_KEYCODE(BUTTON_9), \
    DEFINE_KEYCODE(BUTTON_10), \
    DEFINE_KEYCODE(BUTTON_11), \
    DEFINE_KEYCODE(BUTTON_12), \
    DEFINE_KEYCODE(BUTTON_13), \
    DEFINE_KEYCODE(BUTTON_14), \
    DEFINE_KEYCODE(BUTTON_15), \
    DEFINE_KEYCODE(BUTTON_16), \
    DEFINE_KEYCODE(LANGUAGE_SWITCH), \
    DEFINE_KEYCODE(MANNER_MODE), \
    DEFINE_KEYCODE(3D_MODE), \
    DEFINE_KEYCODE(CONTACTS), \
    DEFINE_KEYCODE(CALENDAR), \
    DEFINE_KEYCODE(MUSIC), \
    DEFINE_KEYCODE(CALCULATOR), \
    DEFINE_KEYCODE(ZENKAKU_HANKAKU), \
    DEFINE_KEYCODE(EISU), \
    DEFINE_KEYCODE(MUHENKAN), \
    DEFINE_KEYCODE(HENKAN), \
    DEFINE_KEYCODE(KATAKANA_HIRAGANA), \
    DEFINE_KEYCODE(YEN), \
    DEFINE_KEYCODE(RO), \
    DEFINE_KEYCODE(KANA), \
    DEFINE_KEYCODE(ASSIST), \
    DEFINE_KEYCODE(BRIGHTNESS_DOWN), \
    DEFINE_KEYCODE(BRIGHTNESS_UP), \
    DEFINE_KEYCODE(MEDIA_AUDIO_TRACK), \
    DEFINE_KEYCODE(SLEEP), \
    DEFINE_KEYCODE(WAKEUP), \
    DEFINE_KEYCODE(PAIRING), \
    DEFINE_KEYCODE(MEDIA_TOP_MENU), \
    DEFINE_KEYCODE(11), \
    DEFINE_KEYCODE(12), \
    DEFINE_KEYCODE(LAST_CHANNEL), \
    DEFINE_KEYCODE(TV_DATA_SERVICE), \
    DEFINE_KEYCODE(VOICE_ASSIST), \
    DEFINE_KEYCODE(TV_RADIO_SERVICE), \
    DEFINE_KEYCODE(TV_TELETEXT), \
    DEFINE_KEYCODE(TV_NUMBER_ENTRY), \
    DEFINE_KEYCODE(TV_TERRESTRIAL_ANALOG), \
    DEFINE_KEYCODE(TV_TERRESTRIAL_DIGITAL), \
    DEFINE_KEYCODE(TV_SATELLITE), \
    DEFINE_KEYCODE(TV_SATELLITE_BS), \
    DEFINE_KEYCODE(TV_SATELLITE_CS), \
    DEFINE_KEYCODE(TV_SATELLITE_SERVICE), \
    DEFINE_KEYCODE(TV_NETWORK), \
    DEFINE_KEYCODE(TV_ANTENNA_CABLE), \
    DEFINE_KEYCODE(TV_INPUT_HDMI_1), \
    DEFINE_KEYCODE(TV_INPUT_HDMI_2), \
    DEFINE_KEYCODE(TV_INPUT_HDMI_3), \
    DEFINE_KEYCODE(TV_INPUT_HDMI_4), \
    DEFINE_KEYCODE(TV_INPUT_COMPOSITE_1), \
    DEFINE_KEYCODE(TV_INPUT_COMPOSITE_2), \
    DEFINE_KEYCODE(TV_INPUT_COMPONENT_1), \
    DEFINE_KEYCODE(TV_INPUT_COMPONENT_2), \
    DEFINE_KEYCODE(TV_INPUT_VGA_1), \
    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION), \
    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION_MIX_UP), \
    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION_MIX_DOWN), \
    DEFINE_KEYCODE(TV_ZOOM_MODE), \
    DEFINE_KEYCODE(TV_CONTENTS_MENU), \
    DEFINE_KEYCODE(TV_MEDIA_CONTEXT_MENU), \
    DEFINE_KEYCODE(TV_TIMER_PROGRAMMING), \
    DEFINE_KEYCODE(HELP), \
    DEFINE_KEYCODE(NAVIGATE_PREVIOUS), \
    DEFINE_KEYCODE(NAVIGATE_NEXT), \
    DEFINE_KEYCODE(NAVIGATE_IN), \
    DEFINE_KEYCODE(NAVIGATE_OUT), \
    DEFINE_KEYCODE(STEM_PRIMARY), \
    DEFINE_KEYCODE(STEM_1), \
    DEFINE_KEYCODE(STEM_2), \
    DEFINE_KEYCODE(STEM_3), \
    DEFINE_KEYCODE(DPAD_UP_LEFT), \
    DEFINE_KEYCODE(DPAD_DOWN_LEFT), \
    DEFINE_KEYCODE(DPAD_UP_RIGHT), \
    DEFINE_KEYCODE(DPAD_DOWN_RIGHT), \
    DEFINE_KEYCODE(MEDIA_SKIP_FORWARD), \
    DEFINE_KEYCODE(MEDIA_SKIP_BACKWARD), \
    DEFINE_KEYCODE(MEDIA_STEP_FORWARD), \
    DEFINE_KEYCODE(MEDIA_STEP_BACKWARD), \
    DEFINE_KEYCODE(SOFT_SLEEP), \
    DEFINE_KEYCODE(CUT), \
    DEFINE_KEYCODE(COPY), \
    DEFINE_KEYCODE(PASTE), \
    DEFINE_KEYCODE(SYSTEM_NAVIGATION_UP), \
    DEFINE_KEYCODE(SYSTEM_NAVIGATION_DOWN), \
    DEFINE_KEYCODE(SYSTEM_NAVIGATION_LEFT), \
    DEFINE_KEYCODE(SYSTEM_NAVIGATION_RIGHT), \
    DEFINE_KEYCODE(ALL_APPS), \
    DEFINE_KEYCODE(REFRESH), \
    DEFINE_KEYCODE(THUMBS_UP), \
    DEFINE_KEYCODE(THUMBS_DOWN), \
    DEFINE_KEYCODE(PROFILE_SWITCH), \
    DEFINE_KEYCODE(VIDEO_APP_1), \
    DEFINE_KEYCODE(VIDEO_APP_2), \
    DEFINE_KEYCODE(VIDEO_APP_3), \
    DEFINE_KEYCODE(VIDEO_APP_4), \
    DEFINE_KEYCODE(VIDEO_APP_5), \
    DEFINE_KEYCODE(VIDEO_APP_6), \
    DEFINE_KEYCODE(VIDEO_APP_7), \
    DEFINE_KEYCODE(VIDEO_APP_8), \
    DEFINE_KEYCODE(FEATURED_APP_1), \
    DEFINE_KEYCODE(FEATURED_APP_2), \
    DEFINE_KEYCODE(FEATURED_APP_3), \
    DEFINE_KEYCODE(FEATURED_APP_4), \
    DEFINE_KEYCODE(DEMO_APP_1), \
    DEFINE_KEYCODE(DEMO_APP_2), \
    DEFINE_KEYCODE(DEMO_APP_3), \
    DEFINE_KEYCODE(DEMO_APP_4), \
    DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_DOWN), \
    DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_UP), \
    DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_TOGGLE), \
    DEFINE_KEYCODE(STYLUS_BUTTON_PRIMARY), \
    DEFINE_KEYCODE(STYLUS_BUTTON_SECONDARY), \
    DEFINE_KEYCODE(STYLUS_BUTTON_TERTIARY), \
    DEFINE_KEYCODE(STYLUS_BUTTON_TAIL), \
    DEFINE_KEYCODE(RECENT_APPS), \
    DEFINE_KEYCODE(MACRO_1), \
    DEFINE_KEYCODE(MACRO_2), \
    DEFINE_KEYCODE(MACRO_3), \
    DEFINE_KEYCODE(MACRO_4)

const std::unordered_map<std::string, int> InputEventLookup::KEYCODES = {KEYCODES_SEQUENCE};
const std::vector<InputEventLabel> InputEventLookup::KEY_NAMES = {KEYCODES_SEQUENCE};

std::optional<int> InputEventLookup::getKeyCodeByLabel(const char* label) {
    return lookupValueByLabel(KEYCODES, label);
}

frameworks/native/include/android/keycodes.h

/**
 * Key codes.
 */
enum {
    /** Unknown key code. */
    AKEYCODE_UNKNOWN         = 0,
    /** Soft Left key.
     * Usually situated below the display on phones and used as a multi-function
     * feature key for selecting a software defined function shown on the bottom left
     * of the display. */
    AKEYCODE_SOFT_LEFT       = 1,
    /** Soft Right key.
     * Usually situated below the display on phones and used as a multi-function
     * feature key for selecting a software defined function shown on the bottom right
     * of the display. */
    AKEYCODE_SOFT_RIGHT      = 2,
    /** Home key.
     * This key is handled by the framework and is never delivered to applications. */
    AKEYCODE_HOME            = 3,
    /** Back key. */
    AKEYCODE_BACK            = 4,
    /** Call key. */
    AKEYCODE_CALL            = 5,
    /** End Call key. */
    AKEYCODE_ENDCALL         = 6,
    /** '0' key. */
    AKEYCODE_0               = 7,
    /** '1' key. */
    AKEYCODE_1               = 8,
    /** '2' key. */
    AKEYCODE_2               = 9,
    /** '3' key. */
    AKEYCODE_3               = 10,
    /** '4' key. */
    AKEYCODE_4               = 11,
    /** '5' key. */
    AKEYCODE_5               = 12,
    /** '6' key. */
    AKEYCODE_6               = 13,
    /** '7' key. */
    AKEYCODE_7               = 14,
    /** '8' key. */
    AKEYCODE_8               = 15,
    /** '9' key. */
    AKEYCODE_9               = 16,
    /** '*' key. */
    AKEYCODE_STAR            = 17,
    /** '#' key. */
    AKEYCODE_POUND           = 18,
    /** Directional Pad Up key.
     * May also be synthesized from trackball motions. */
    AKEYCODE_DPAD_UP         = 19,
    /** Directional Pad Down key.
     * May also be synthesized from trackball motions. */
    AKEYCODE_DPAD_DOWN       = 20,
    /** Directional Pad Left key.
     * May also be synthesized from trackball motions. */
    AKEYCODE_DPAD_LEFT       = 21,
    /** Directional Pad Right key.
     * May also be synthesized from trackball motions. */
    AKEYCODE_DPAD_RIGHT      = 22,
    /** Directional Pad Center key.
     * May also be synthesized from trackball motions. */
    AKEYCODE_DPAD_CENTER     = 23,
    /** Volume Up key.
     * Adjusts the speaker volume up. */
    AKEYCODE_VOLUME_UP       = 24,
    /** Volume Down key.
     * Adjusts the speaker volume down. */
    AKEYCODE_VOLUME_DOWN     = 25,
    /** Power key. */
    AKEYCODE_POWER           = 26,
    /** Camera key.
     * Used to launch a camera application or take pictures. */
    AKEYCODE_CAMERA          = 27,
    /** Clear key. */
    AKEYCODE_CLEAR           = 28,
    /** 'A' key. */
    AKEYCODE_A               = 29,
    /** 'B' key. */
    AKEYCODE_B               = 30,
    /** 'C' key. */
    AKEYCODE_C               = 31,
    /** 'D' key. */
    AKEYCODE_D               = 32,
    /** 'E' key. */
    AKEYCODE_E               = 33,
    /** 'F' key. */
    AKEYCODE_F               = 34,
    /** 'G' key. */
    AKEYCODE_G               = 35,
    /** 'H' key. */
    AKEYCODE_H               = 36,
    /** 'I' key. */
    AKEYCODE_I               = 37,
    /** 'J' key. */
    AKEYCODE_J               = 38,
    /** 'K' key. */
    AKEYCODE_K               = 39,
    /** 'L' key. */
    AKEYCODE_L               = 40,
    /** 'M' key. */
    AKEYCODE_M               = 41,
    /** 'N' key. */
    AKEYCODE_N               = 42,
    /** 'O' key. */
    AKEYCODE_O               = 43,
    /** 'P' key. */
    AKEYCODE_P               = 44,
    /** 'Q' key. */
    AKEYCODE_Q               = 45,
    /** 'R' key. */
    AKEYCODE_R               = 46,
    /** 'S' key. */
    AKEYCODE_S               = 47,
    /** 'T' key. */
    AKEYCODE_T               = 48,
    /** 'U' key. */
    AKEYCODE_U               = 49,
    /** 'V' key. */
    AKEYCODE_V               = 50,
    /** 'W' key. */
    AKEYCODE_W               = 51,
    /** 'X' key. */
    AKEYCODE_X               = 52,
    /** 'Y' key. */
    AKEYCODE_Y               = 53,
    /** 'Z' key. */
    AKEYCODE_Z               = 54,
    /** ',' key. */
    AKEYCODE_COMMA           = 55,
    /** '.' key. */
    AKEYCODE_PERIOD          = 56,
    /** Left Alt modifier key. */
    AKEYCODE_ALT_LEFT        = 57,
    /** Right Alt modifier key. */
    AKEYCODE_ALT_RIGHT       = 58,
    /** Left Shift modifier key. */
    AKEYCODE_SHIFT_LEFT      = 59,
    /** Right Shift modifier key. */
    AKEYCODE_SHIFT_RIGHT     = 60,
    /** Tab key. */
    AKEYCODE_TAB             = 61,
    /** Space key. */
    AKEYCODE_SPACE           = 62,
    /** Symbol modifier key.
     * Used to enter alternate symbols. */
    AKEYCODE_SYM             = 63,
    /** Explorer special function key.
     * Used to launch a browser application. */
    AKEYCODE_EXPLORER        = 64,
    /** Envelope special function key.
     * Used to launch a mail application. */
    AKEYCODE_ENVELOPE        = 65,
    /** Enter key. */
    AKEYCODE_ENTER           = 66,
    /** Backspace key.
     * Deletes characters before the insertion point, unlike {@link AKEYCODE_FORWARD_DEL}. */
    AKEYCODE_DEL             = 67,
    /** '`' (backtick) key. */
    AKEYCODE_GRAVE           = 68,
    /** '-'. */
    AKEYCODE_MINUS           = 69,
    /** '=' key. */
    AKEYCODE_EQUALS          = 70,
    /** '[' key. */
    AKEYCODE_LEFT_BRACKET    = 71,
    /** ']' key. */
    AKEYCODE_RIGHT_BRACKET   = 72,
    /** '\' key. */
    AKEYCODE_BACKSLASH       = 73,
    /** ';' key. */
    AKEYCODE_SEMICOLON       = 74,
    /** ''' (apostrophe) key. */
    AKEYCODE_APOSTROPHE      = 75,
    /** '/' key. */
    AKEYCODE_SLASH           = 76,
    /** '@' key. */
    AKEYCODE_AT              = 77,
    /** Number modifier key.
     * Used to enter numeric symbols.
     * This key is not {@link AKEYCODE_NUM_LOCK}; it is more like {@link AKEYCODE_ALT_LEFT}. */
    AKEYCODE_NUM             = 78,
    /** Headset Hook key.
     * Used to hang up calls and stop media. */
    AKEYCODE_HEADSETHOOK     = 79,
    /** Camera Focus key.
     * Used to focus the camera. */
    AKEYCODE_FOCUS           = 80,
    /** '+' key. */
    AKEYCODE_PLUS            = 81,
    /** Menu key. */
    AKEYCODE_MENU            = 82,
    /** Notification key. */
    AKEYCODE_NOTIFICATION    = 83,
    /** Search key. */
    AKEYCODE_SEARCH          = 84,
    /** Play/Pause media key. */
    AKEYCODE_MEDIA_PLAY_PAUSE= 85,
    /** Stop media key. */
    AKEYCODE_MEDIA_STOP      = 86,
    /** Play Next media key. */
    AKEYCODE_MEDIA_NEXT      = 87,
    /** Play Previous media key. */
    AKEYCODE_MEDIA_PREVIOUS  = 88,
    /** Rewind media key. */
    AKEYCODE_MEDIA_REWIND    = 89,
    /** Fast Forward media key. */
    AKEYCODE_MEDIA_FAST_FORWARD = 90,
    /** Mute key.
     * Mutes the microphone, unlike {@link AKEYCODE_VOLUME_MUTE}. */
    AKEYCODE_MUTE            = 91,
    /** Page Up key. */
    AKEYCODE_PAGE_UP         = 92,
    /** Page Down key. */
    AKEYCODE_PAGE_DOWN       = 93,
    /** Picture Symbols modifier key.
     * Used to switch symbol sets (Emoji, Kao-moji). */
    AKEYCODE_PICTSYMBOLS     = 94,
    /** Switch Charset modifier key.
     * Used to switch character sets (Kanji, Katakana). */
    AKEYCODE_SWITCH_CHARSET  = 95,
    /** A Button key.
     * On a game controller, the A button should be either the button labeled A
     * or the first button on the bottom row of controller buttons. */
    AKEYCODE_BUTTON_A        = 96,
    /** B Button key.
     * On a game controller, the B button should be either the button labeled B
     * or the second button on the bottom row of controller buttons. */
    AKEYCODE_BUTTON_B        = 97,
    /** C Button key.
     * On a game controller, the C button should be either the button labeled C
     * or the third button on the bottom row of controller buttons. */
    AKEYCODE_BUTTON_C        = 98,
    /** X Button key.
     * On a game controller, the X button should be either the button labeled X
     * or the first button on the upper row of controller buttons. */
    AKEYCODE_BUTTON_X        = 99,
    /** Y Button key.
     * On a game controller, the Y button should be either the button labeled Y
     * or the second button on the upper row of controller buttons. */
    AKEYCODE_BUTTON_Y        = 100,
    /** Z Button key.
     * On a game controller, the Z button should be either the button labeled Z
     * or the third button on the upper row of controller buttons. */
    AKEYCODE_BUTTON_Z        = 101,
    /** L1 Button key.
     * On a game controller, the L1 button should be either the button labeled L1 (or L)
     * or the top left trigger button. */
    AKEYCODE_BUTTON_L1       = 102,
    /** R1 Button key.
     * On a game controller, the R1 button should be either the button labeled R1 (or R)
     * or the top right trigger button. */
    AKEYCODE_BUTTON_R1       = 103,
    /** L2 Button key.
     * On a game controller, the L2 button should be either the button labeled L2
     * or the bottom left trigger button. */
    AKEYCODE_BUTTON_L2       = 104,
    /** R2 Button key.
     * On a game controller, the R2 button should be either the button labeled R2
     * or the bottom right trigger button. */
    AKEYCODE_BUTTON_R2       = 105,
    /** Left Thumb Button key.
     * On a game controller, the left thumb button indicates that the left (or only)
     * joystick is pressed. */
    AKEYCODE_BUTTON_THUMBL   = 106,
    /** Right Thumb Button key.
     * On a game controller, the right thumb button indicates that the right
     * joystick is pressed. */
    AKEYCODE_BUTTON_THUMBR   = 107,
    /** Start Button key.
     * On a game controller, the button labeled Start. */
    AKEYCODE_BUTTON_START    = 108,
    /** Select Button key.
     * On a game controller, the button labeled Select. */
    AKEYCODE_BUTTON_SELECT   = 109,
    /** Mode Button key.
     * On a game controller, the button labeled Mode. */
    AKEYCODE_BUTTON_MODE     = 110,
    /** Escape key. */
    AKEYCODE_ESCAPE          = 111,
    /** Forward Delete key.
     * Deletes characters ahead of the insertion point, unlike {@link AKEYCODE_DEL}. */
    AKEYCODE_FORWARD_DEL     = 112,
    /** Left Control modifier key. */
    AKEYCODE_CTRL_LEFT       = 113,
    /** Right Control modifier key. */
    AKEYCODE_CTRL_RIGHT      = 114,
    /** Caps Lock key. */
    AKEYCODE_CAPS_LOCK       = 115,
    /** Scroll Lock key. */
    AKEYCODE_SCROLL_LOCK     = 116,
    /** Left Meta modifier key. */
    AKEYCODE_META_LEFT       = 117,
    /** Right Meta modifier key. */
    AKEYCODE_META_RIGHT      = 118,
    /** Function modifier key. */
    AKEYCODE_FUNCTION        = 119,
    /** System Request / Print Screen key. */
    AKEYCODE_SYSRQ           = 120,
    /** Break / Pause key. */
    AKEYCODE_BREAK           = 121,
    /** Home Movement key.
     * Used for scrolling or moving the cursor around to the start of a line
     * or to the top of a list. */
    AKEYCODE_MOVE_HOME       = 122,
    /** End Movement key.
     * Used for scrolling or moving the cursor around to the end of a line
     * or to the bottom of a list. */
    AKEYCODE_MOVE_END        = 123,
    /** Insert key.
     * Toggles insert / overwrite edit mode. */
    AKEYCODE_INSERT          = 124,
    /** Forward key.
     * Navigates forward in the history stack.  Complement of {@link AKEYCODE_BACK}. */
    AKEYCODE_FORWARD         = 125,
    /** Play media key. */
    AKEYCODE_MEDIA_PLAY      = 126,
    /** Pause media key. */
    AKEYCODE_MEDIA_PAUSE     = 127,
    /** Close media key.
     * May be used to close a CD tray, for example. */
    AKEYCODE_MEDIA_CLOSE     = 128,
    /** Eject media key.
     * May be used to eject a CD tray, for example. */
    AKEYCODE_MEDIA_EJECT     = 129,
    /** Record media key. */
    AKEYCODE_MEDIA_RECORD    = 130,
    /** F1 key. */
    AKEYCODE_F1              = 131,
    /** F2 key. */
    AKEYCODE_F2              = 132,
    /** F3 key. */
    AKEYCODE_F3              = 133,
    /** F4 key. */
    AKEYCODE_F4              = 134,
    /** F5 key. */
    AKEYCODE_F5              = 135,
    /** F6 key. */
    AKEYCODE_F6              = 136,
    /** F7 key. */
    AKEYCODE_F7              = 137,
    /** F8 key. */
    AKEYCODE_F8              = 138,
    /** F9 key. */
    AKEYCODE_F9              = 139,
    /** F10 key. */
    AKEYCODE_F10             = 140,
    /** F11 key. */
    AKEYCODE_F11             = 141,
    /** F12 key. */
    AKEYCODE_F12             = 142,
    /** Num Lock key.
     * This is the Num Lock key; it is different from {@link AKEYCODE_NUM}.
     * This key alters the behavior of other keys on the numeric keypad. */
    AKEYCODE_NUM_LOCK        = 143,
    /** Numeric keypad '0' key. */
    AKEYCODE_NUMPAD_0        = 144,
    /** Numeric keypad '1' key. */
    AKEYCODE_NUMPAD_1        = 145,
    /** Numeric keypad '2' key. */
    AKEYCODE_NUMPAD_2        = 146,
    /** Numeric keypad '3' key. */
    AKEYCODE_NUMPAD_3        = 147,
    /** Numeric keypad '4' key. */
    AKEYCODE_NUMPAD_4        = 148,
    /** Numeric keypad '5' key. */
    AKEYCODE_NUMPAD_5        = 149,
    /** Numeric keypad '6' key. */
    AKEYCODE_NUMPAD_6        = 150,
    /** Numeric keypad '7' key. */
    AKEYCODE_NUMPAD_7        = 151,
    /** Numeric keypad '8' key. */
    AKEYCODE_NUMPAD_8        = 152,
    /** Numeric keypad '9' key. */
    AKEYCODE_NUMPAD_9        = 153,
    /** Numeric keypad '/' key (for division). */
    AKEYCODE_NUMPAD_DIVIDE   = 154,
    /** Numeric keypad '*' key (for multiplication). */
    AKEYCODE_NUMPAD_MULTIPLY = 155,
    /** Numeric keypad '-' key (for subtraction). */
    AKEYCODE_NUMPAD_SUBTRACT = 156,
    /** Numeric keypad '+' key (for addition). */
    AKEYCODE_NUMPAD_ADD      = 157,
    /** Numeric keypad '.' key (for decimals or digit grouping). */
    AKEYCODE_NUMPAD_DOT      = 158,
    /** Numeric keypad ',' key (for decimals or digit grouping). */
    AKEYCODE_NUMPAD_COMMA    = 159,
    /** Numeric keypad Enter key. */
    AKEYCODE_NUMPAD_ENTER    = 160,
    /** Numeric keypad '=' key. */
    AKEYCODE_NUMPAD_EQUALS   = 161,
    /** Numeric keypad '(' key. */
    AKEYCODE_NUMPAD_LEFT_PAREN = 162,
    /** Numeric keypad ')' key. */
    AKEYCODE_NUMPAD_RIGHT_PAREN = 163,
    /** Volume Mute key.
     * Mutes the speaker, unlike {@link AKEYCODE_MUTE}.
     * This key should normally be implemented as a toggle such that the first press
     * mutes the speaker and the second press restores the original volume. */
    AKEYCODE_VOLUME_MUTE     = 164,
    /** Info key.
     * Common on TV remotes to show additional information related to what is
     * currently being viewed. */
    AKEYCODE_INFO            = 165,
    /** Channel up key.
     * On TV remotes, increments the television channel. */
    AKEYCODE_CHANNEL_UP      = 166,
    /** Channel down key.
     * On TV remotes, decrements the television channel. */
    AKEYCODE_CHANNEL_DOWN    = 167,
    /** Zoom in key. */
    AKEYCODE_ZOOM_IN         = 168,
    /** Zoom out key. */
    AKEYCODE_ZOOM_OUT        = 169,
    /** TV key.
     * On TV remotes, switches to viewing live TV. */
    AKEYCODE_TV              = 170,
    /** Window key.
     * On TV remotes, toggles picture-in-picture mode or other windowing functions. */
    AKEYCODE_WINDOW          = 171,
    /** Guide key.
     * On TV remotes, shows a programming guide. */
    AKEYCODE_GUIDE           = 172,
    /** DVR key.
     * On some TV remotes, switches to a DVR mode for recorded shows. */
    AKEYCODE_DVR             = 173,
    /** Bookmark key.
     * On some TV remotes, bookmarks content or web pages. */
    AKEYCODE_BOOKMARK        = 174,
    /** Toggle captions key.
     * Switches the mode for closed-captioning text, for example during television shows. */
    AKEYCODE_CAPTIONS        = 175,
    /** Settings key.
     * Starts the system settings activity. */
    AKEYCODE_SETTINGS        = 176,
    /** TV power key.
     * On TV remotes, toggles the power on a television screen. */
    AKEYCODE_TV_POWER        = 177,
    /** TV input key.
     * On TV remotes, switches the input on a television screen. */
    AKEYCODE_TV_INPUT        = 178,
    /** Set-top-box power key.
     * On TV remotes, toggles the power on an external Set-top-box. */
    AKEYCODE_STB_POWER       = 179,
    /** Set-top-box input key.
     * On TV remotes, switches the input mode on an external Set-top-box. */
    AKEYCODE_STB_INPUT       = 180,
    /** A/V Receiver power key.
     * On TV remotes, toggles the power on an external A/V Receiver. */
    AKEYCODE_AVR_POWER       = 181,
    /** A/V Receiver input key.
     * On TV remotes, switches the input mode on an external A/V Receiver. */
    AKEYCODE_AVR_INPUT       = 182,
    /** Red "programmable" key.
     * On TV remotes, acts as a contextual/programmable key. */
    AKEYCODE_PROG_RED        = 183,
    /** Green "programmable" key.
     * On TV remotes, actsas a contextual/programmable key. */
    AKEYCODE_PROG_GREEN      = 184,
    /** Yellow "programmable" key.
     * On TV remotes, acts as a contextual/programmable key. */
    AKEYCODE_PROG_YELLOW     = 185,
    /** Blue "programmable" key.
     * On TV remotes, acts as a contextual/programmable key. */
    AKEYCODE_PROG_BLUE       = 186,
    /** App switch key.
     * Should bring up the application switcher dialog. */
    AKEYCODE_APP_SWITCH      = 187,
    /** Generic Game Pad Button #1.*/
    AKEYCODE_BUTTON_1        = 188,
    /** Generic Game Pad Button #2.*/
    AKEYCODE_BUTTON_2        = 189,
    /** Generic Game Pad Button #3.*/
    AKEYCODE_BUTTON_3        = 190,
    /** Generic Game Pad Button #4.*/
    AKEYCODE_BUTTON_4        = 191,
    /** Generic Game Pad Button #5.*/
    AKEYCODE_BUTTON_5        = 192,
    /** Generic Game Pad Button #6.*/
    AKEYCODE_BUTTON_6        = 193,
    /** Generic Game Pad Button #7.*/
    AKEYCODE_BUTTON_7        = 194,
    /** Generic Game Pad Button #8.*/
    AKEYCODE_BUTTON_8        = 195,
    /** Generic Game Pad Button #9.*/
    AKEYCODE_BUTTON_9        = 196,
    /** Generic Game Pad Button #10.*/
    AKEYCODE_BUTTON_10       = 197,
    /** Generic Game Pad Button #11.*/
    AKEYCODE_BUTTON_11       = 198,
    /** Generic Game Pad Button #12.*/
    AKEYCODE_BUTTON_12       = 199,
    /** Generic Game Pad Button #13.*/
    AKEYCODE_BUTTON_13       = 200,
    /** Generic Game Pad Button #14.*/
    AKEYCODE_BUTTON_14       = 201,
    /** Generic Game Pad Button #15.*/
    AKEYCODE_BUTTON_15       = 202,
    /** Generic Game Pad Button #16.*/
    AKEYCODE_BUTTON_16       = 203,
    /** Language Switch key.
     * Toggles the current input language such as switching between English and Japanese on
     * a QWERTY keyboard.  On some devices, the same function may be performed by
     * pressing Shift+Spacebar. */
    AKEYCODE_LANGUAGE_SWITCH = 204,
    /** Manner Mode key.
     * Toggles silent or vibrate mode on and off to make the device behave more politely
     * in certain settings such as on a crowded train.  On some devices, the key may only
     * operate when long-pressed. */
    AKEYCODE_MANNER_MODE     = 205,
    /** 3D Mode key.
     * Toggles the display between 2D and 3D mode. */
    AKEYCODE_3D_MODE         = 206,
    /** Contacts special function key.
     * Used to launch an address book application. */
    AKEYCODE_CONTACTS        = 207,
    /** Calendar special function key.
     * Used to launch a calendar application. */
    AKEYCODE_CALENDAR        = 208,
    /** Music special function key.
     * Used to launch a music player application. */
    AKEYCODE_MUSIC           = 209,
    /** Calculator special function key.
     * Used to launch a calculator application. */
    AKEYCODE_CALCULATOR      = 210,
    /** Japanese full-width / half-width key. */
    AKEYCODE_ZENKAKU_HANKAKU = 211,
    /** Japanese alphanumeric key. */
    AKEYCODE_EISU            = 212,
    /** Japanese non-conversion key. */
    AKEYCODE_MUHENKAN        = 213,
    /** Japanese conversion key. */
    AKEYCODE_HENKAN          = 214,
    /** Japanese katakana / hiragana key. */
    AKEYCODE_KATAKANA_HIRAGANA = 215,
    /** Japanese Yen key. */
    AKEYCODE_YEN             = 216,
    /** Japanese Ro key. */
    AKEYCODE_RO              = 217,
    /** Japanese kana key. */
    AKEYCODE_KANA            = 218,
    /** Assist key.
     * Launches the global assist activity.  Not delivered to applications. */
    AKEYCODE_ASSIST          = 219,
    /** Brightness Down key.
     * Adjusts the screen brightness down. */
    AKEYCODE_BRIGHTNESS_DOWN = 220,
    /** Brightness Up key.
     * Adjusts the screen brightness up. */
    AKEYCODE_BRIGHTNESS_UP   = 221,
    /** Audio Track key.
     * Switches the audio tracks. */
    AKEYCODE_MEDIA_AUDIO_TRACK = 222,
    /** Sleep key.
     * Puts the device to sleep.  Behaves somewhat like {@link AKEYCODE_POWER} but it
     * has no effect if the device is already asleep. */
    AKEYCODE_SLEEP           = 223,
    /** Wakeup key.
     * Wakes up the device.  Behaves somewhat like {@link AKEYCODE_POWER} but it
     * has no effect if the device is already awake. */
    AKEYCODE_WAKEUP          = 224,
    /** Pairing key.
     * Initiates peripheral pairing mode. Useful for pairing remote control
     * devices or game controllers, especially if no other input mode is
     * available. */
    AKEYCODE_PAIRING         = 225,
    /** Media Top Menu key.
     * Goes to the top of media menu. */
    AKEYCODE_MEDIA_TOP_MENU  = 226,
    /** '11' key. */
    AKEYCODE_11              = 227,
    /** '12' key. */
    AKEYCODE_12              = 228,
    /** Last Channel key.
     * Goes to the last viewed channel. */
    AKEYCODE_LAST_CHANNEL    = 229,
    /** TV data service key.
     * Displays data services like weather, sports. */
    AKEYCODE_TV_DATA_SERVICE = 230,
    /** Voice Assist key.
     * Launches the global voice assist activity. Not delivered to applications. */
    AKEYCODE_VOICE_ASSIST    = 231,
    /** Radio key.
     * Toggles TV service / Radio service. */
    AKEYCODE_TV_RADIO_SERVICE = 232,
    /** Teletext key.
     * Displays Teletext service. */
    AKEYCODE_TV_TELETEXT     = 233,
    /** Number entry key.
     * Initiates to enter multi-digit channel nubmber when each digit key is assigned
     * for selecting separate channel. Corresponds to Number Entry Mode (0x1D) of CEC
     * User Control Code. */
    AKEYCODE_TV_NUMBER_ENTRY = 234,
    /** Analog Terrestrial key.
     * Switches to analog terrestrial broadcast service. */
    AKEYCODE_TV_TERRESTRIAL_ANALOG = 235,
    /** Digital Terrestrial key.
     * Switches to digital terrestrial broadcast service. */
    AKEYCODE_TV_TERRESTRIAL_DIGITAL = 236,
    /** Satellite key.
     * Switches to digital satellite broadcast service. */
    AKEYCODE_TV_SATELLITE    = 237,
    /** BS key.
     * Switches to BS digital satellite broadcasting service available in Japan. */
    AKEYCODE_TV_SATELLITE_BS = 238,
    /** CS key.
     * Switches to CS digital satellite broadcasting service available in Japan. */
    AKEYCODE_TV_SATELLITE_CS = 239,
    /** BS/CS key.
     * Toggles between BS and CS digital satellite services. */
    AKEYCODE_TV_SATELLITE_SERVICE = 240,
    /** Toggle Network key.
     * Toggles selecting broacast services. */
    AKEYCODE_TV_NETWORK      = 241,
    /** Antenna/Cable key.
     * Toggles broadcast input source between antenna and cable. */
    AKEYCODE_TV_ANTENNA_CABLE = 242,
    /** HDMI #1 key.
     * Switches to HDMI input #1. */
    AKEYCODE_TV_INPUT_HDMI_1 = 243,
    /** HDMI #2 key.
     * Switches to HDMI input #2. */
    AKEYCODE_TV_INPUT_HDMI_2 = 244,
    /** HDMI #3 key.
     * Switches to HDMI input #3. */
    AKEYCODE_TV_INPUT_HDMI_3 = 245,
    /** HDMI #4 key.
     * Switches to HDMI input #4. */
    AKEYCODE_TV_INPUT_HDMI_4 = 246,
    /** Composite #1 key.
     * Switches to composite video input #1. */
    AKEYCODE_TV_INPUT_COMPOSITE_1 = 247,
    /** Composite #2 key.
     * Switches to composite video input #2. */
    AKEYCODE_TV_INPUT_COMPOSITE_2 = 248,
    /** Component #1 key.
     * Switches to component video input #1. */
    AKEYCODE_TV_INPUT_COMPONENT_1 = 249,
    /** Component #2 key.
     * Switches to component video input #2. */
    AKEYCODE_TV_INPUT_COMPONENT_2 = 250,
    /** VGA #1 key.
     * Switches to VGA (analog RGB) input #1. */
    AKEYCODE_TV_INPUT_VGA_1  = 251,
    /** Audio description key.
     * Toggles audio description off / on. */
    AKEYCODE_TV_AUDIO_DESCRIPTION = 252,
    /** Audio description mixing volume up key.
     * Louden audio description volume as compared with normal audio volume. */
    AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253,
    /** Audio description mixing volume down key.
     * Lessen audio description volume as compared with normal audio volume. */
    AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254,
    /** Zoom mode key.
     * Changes Zoom mode (Normal, Full, Zoom, Wide-zoom, etc.) */
    AKEYCODE_TV_ZOOM_MODE    = 255,
    /** Contents menu key.
     * Goes to the title list. Corresponds to Contents Menu (0x0B) of CEC User Control
     * Code */
    AKEYCODE_TV_CONTENTS_MENU = 256,
    /** Media context menu key.
     * Goes to the context menu of media contents. Corresponds to Media Context-sensitive
     * Menu (0x11) of CEC User Control Code. */
    AKEYCODE_TV_MEDIA_CONTEXT_MENU = 257,
    /** Timer programming key.
     * Goes to the timer recording menu. Corresponds to Timer Programming (0x54) of
     * CEC User Control Code. */
    AKEYCODE_TV_TIMER_PROGRAMMING = 258,
    /** Help key. */
    AKEYCODE_HELP            = 259,
    AKEYCODE_NAVIGATE_PREVIOUS = 260,
    AKEYCODE_NAVIGATE_NEXT   = 261,
    AKEYCODE_NAVIGATE_IN     = 262,
    AKEYCODE_NAVIGATE_OUT    = 263,
    /** Primary stem key for Wear
     * Main power/reset button on watch. */
    AKEYCODE_STEM_PRIMARY = 264,
    /** Generic stem key 1 for Wear */
    AKEYCODE_STEM_1 = 265,
    /** Generic stem key 2 for Wear */
    AKEYCODE_STEM_2 = 266,
    /** Generic stem key 3 for Wear */
    AKEYCODE_STEM_3 = 267,
    /** Directional Pad Up-Left */
    AKEYCODE_DPAD_UP_LEFT    = 268,
    /** Directional Pad Down-Left */
    AKEYCODE_DPAD_DOWN_LEFT  = 269,
    /** Directional Pad Up-Right */
    AKEYCODE_DPAD_UP_RIGHT   = 270,
    /** Directional Pad Down-Right */
    AKEYCODE_DPAD_DOWN_RIGHT = 271,
    /** Skip forward media key */
    AKEYCODE_MEDIA_SKIP_FORWARD = 272,
    /** Skip backward media key */
    AKEYCODE_MEDIA_SKIP_BACKWARD = 273,
    /** Step forward media key.
     * Steps media forward one from at a time. */
    AKEYCODE_MEDIA_STEP_FORWARD = 274,
    /** Step backward media key.
     * Steps media backward one from at a time. */
    AKEYCODE_MEDIA_STEP_BACKWARD = 275,
    /** Put device to sleep unless a wakelock is held. */
    AKEYCODE_SOFT_SLEEP = 276,
    /** Cut key. */
    AKEYCODE_CUT = 277,
    /** Copy key. */
    AKEYCODE_COPY = 278,
    /** Paste key. */
    AKEYCODE_PASTE = 279,
    /** fingerprint navigation key, up. */
    AKEYCODE_SYSTEM_NAVIGATION_UP = 280,
    /** fingerprint navigation key, down. */
    AKEYCODE_SYSTEM_NAVIGATION_DOWN = 281,
    /** fingerprint navigation key, left. */
    AKEYCODE_SYSTEM_NAVIGATION_LEFT = 282,
    /** fingerprint navigation key, right. */
    AKEYCODE_SYSTEM_NAVIGATION_RIGHT = 283,
    /** all apps */
    AKEYCODE_ALL_APPS = 284,
    /** refresh key */
    AKEYCODE_REFRESH = 285,
    /** Thumbs up key. Apps can use this to let user upvote content. */
    AKEYCODE_THUMBS_UP = 286,
    /** Thumbs down key. Apps can use this to let user downvote content. */
    AKEYCODE_THUMBS_DOWN = 287,
    /** Used to switch current account that is consuming content.
     * May be consumed by system to switch current viewer profile. */
    AKEYCODE_PROFILE_SWITCH = 288,
    /** Video Application key #1. */
    AKEYCODE_VIDEO_APP_1 = 289,
    /** Video Application key #2. */
    AKEYCODE_VIDEO_APP_2 = 290,
    /** Video Application key #3. */
    AKEYCODE_VIDEO_APP_3 = 291,
    /** Video Application key #4. */
    AKEYCODE_VIDEO_APP_4 = 292,
    /** Video Application key #5. */
    AKEYCODE_VIDEO_APP_5 = 293,
    /** Video Application key #6. */
    AKEYCODE_VIDEO_APP_6 = 294,
    /** Video Application key #7. */
    AKEYCODE_VIDEO_APP_7 = 295,
    /** Video Application key #8. */
    AKEYCODE_VIDEO_APP_8 = 296,
    /** Featured Application key #1. */
    AKEYCODE_FEATURED_APP_1 = 297,
    /** Featured Application key #2. */
    AKEYCODE_FEATURED_APP_2 = 298,
    /** Featured Application key #3. */
    AKEYCODE_FEATURED_APP_3 = 299,
    /** Featured Application key #4. */
    AKEYCODE_FEATURED_APP_4 = 300,
    /** Demo Application key #1. */
    AKEYCODE_DEMO_APP_1 = 301,
    /** Demo Application key #2. */
    AKEYCODE_DEMO_APP_2 = 302,
    /** Demo Application key #3. */
    AKEYCODE_DEMO_APP_3 = 303,
    /** Demo Application key #4. */
    AKEYCODE_DEMO_APP_4 = 304,
    /** Keyboard backlight Down key.
     * Adjusts the keyboard backlight brightness down. */
    AKEYCODE_KEYBOARD_BACKLIGHT_DOWN = 305,
    /** Keyboard backlight Up key.
     * Adjusts the keyboard backlight brightness up. */
    AKEYCODE_KEYBOARD_BACKLIGHT_UP = 306,
    /** Keyboard backlight Toggle key.
     * Toggles the keyboard backlight on/off. */
    AKEYCODE_KEYBOARD_BACKLIGHT_TOGGLE = 307,
    /** The primary button on the barrel of a stylus.
     * This is usually the button closest to the tip of the stylus. */
    AKEYCODE_STYLUS_BUTTON_PRIMARY = 308,
    /** The secondary button on the barrel of a stylus.
     * This is usually the second button from the tip of the stylus. */
    AKEYCODE_STYLUS_BUTTON_SECONDARY = 309,
    /** The tertiary button on the barrel of a stylus.
     * This is usually the third button from the tip of the stylus. */
    AKEYCODE_STYLUS_BUTTON_TERTIARY = 310,
    /** A button on the tail end of a stylus. */
    AKEYCODE_STYLUS_BUTTON_TAIL = 311,
    /** Key to open recent apps (a.k.a. Overview) */
    AKEYCODE_RECENT_APPS = 312,
    /** User customizable key #1. */
    AKEYCODE_MACRO_1 = 313,
    /** User customizable key #2. */
    AKEYCODE_MACRO_2 = 314,
    /** User customizable key #3. */
    AKEYCODE_MACRO_3 = 315,
    /** User customizable key #4. */
    AKEYCODE_MACRO_4 = 316,

    // NOTE: If you add a new keycode here you must also add it to several other files.
    //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
};

4、KeyEvent.java 添加对应keycode

frameworks/base/core/java/android/view/KeyEvent.java

    /**
     * Key code constant: A button whose usage can be customized by the user through
     *                    the system.
     * User customizable key #4.
     */
    public static final int KEYCODE_MACRO_4 = 316;


   /**
     * Integer value of the last KEYCODE. Increases as new keycodes are added to KeyEvent.
     * @hide
     */
    @TestApi
    public static final int LAST_KEYCODE = KEYCODE_MACRO_4;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/887824.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

京东云主机怎么用?使用京东云服务器建网站(图文教程)

京东云主机怎么用&#xff1f;非常简单&#xff0c;本文京东云服务器网jdyfwq.com使用以使用京东云服务器搭建WordPress博客网站为例&#xff0c;来详细说下京东云主机的使用方法。使用京东云服务器快速搭建WordPress网站教程&#xff0c;3分钟基于应用镜像一键搞定&#xff0c…

python之详解字符串

由字符组成的序列&#xff0c;可以用单引号或双引号括起来。 1、通过下标获取字符串的字符 1.1、获取单个字符 若要获取字符串中某一个字符&#xff0c;可以通过 字符串名[index] 索引下标的方式获取。 索引的初始值为0&#xff0c;最大值为字符串长度-1。 切记&#xff0…

一、图解C#教程

一、堆和栈 程序运行时&#xff0c;数据存储在内存中。 使用堆和栈来存储数据 1、栈 栈是一个内存数组&#xff0c;先进后出原则。 可以存储&#xff1a;某些类型变量的值&#xff1b;程序当前执行环境&#xff1b;传递给方法的参数&#xff1b; 入栈&#xff1a;把数据放…

自动驾驶-问题笔记-待解决

参考线的平滑方法 参考线平滑算法主要有三种&#xff1a; 离散点平滑&#xff1b;螺旋曲线平滑&#xff1b;多项式平滑&#xff1b; 参考链接&#xff1a;参考线平滑 对于平滑方法&#xff0c;一直不太理解平滑、拟合以及滤波三者的作用与区别&#xff1b; 规划的起点&#x…

计算机网络——email

pop3拉出来 超出ASCII码范围就不让传了 这样就可以传更大的文件

Ubuntu 安装 Docker Compose

安装Docker Compose # 删除现有的 docker-compose&#xff08;如果存在&#xff09; sudo rm -f /usr/local/bin/docker-compose ​ # 下载最新的 docker-compose 二进制文件 sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-…

JavaScript for循环语句

for循环 循环语句用于重复执行某个操作&#xff0c;for语句就是循环命令&#xff0c;可以指定循环的起点、终点和终止条件。它的格式如下 for(初始化表达式;条件;迭代因子){语句} for语句后面的括号里面&#xff0c;有三个表达式 初始化表达式(initialize):确定循环变量的初始…

[C语言]指针和数组

目录 1.数组的地址 2.通过指针访问数组 3.数组和指针的不同点 4.指针数组 1.数组的地址 数组的地址是什么&#xff1f; 看下面一组代码 #include <stdio.h> int main() { int arr[5] {5,4,3,2,1}; printf("&arr[0] %p\n", &arr[0]); printf(&qu…

LeetCode讲解篇之139. 单词拆分

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们使用一个数组记录字符串s在[0, i)区间能否使用wordDict组成 我们使用左右指针遍历字符串s的子串&#xff0c;左指针 j 为子串的左端点下标&#xff0c;右指针 i 为右端点下标的下一个 遍历过程中如果字符串s…

自然语言处理问答系统

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

字节放大招:无需LORA训练,小红书写真轻松搞定,Pulid-Flux换脸方案来了

前言 在这之前&#xff0c;SD常用的换脸节点还不支持Flux模型&#xff0c;使用Flux 做虚拟模特最好的方法是炼制人脸lora&#xff0c;但是炼丹是个有技术门槛的活。 之前文章有提过字节跳动的 Pulid团队&#xff0c;率先推出了Pulid-Flux模型&#xff0c;但是之前只能在线上使用…

【Redis】Hash类型的常用命令

背景&#xff1a;redis中存储数据采取key-value键值对的形式&#xff0c;而hash内部也是键值对&#xff0c;为了区别这两个东西&#xff0c;hash内部的键值对称为&#xff1a;field-value&#xff0c;而redis的为key-value&#xff0c;这里的value包括&#xff1a;field-value。…

Elasticsearch基础_5.ES聚合功能

文章目录 一、数据聚合1.1、桶聚合1.1.1、单维度桶聚合1.1.2、聚合结果排序1.1.3、限定聚合范围 1.2、Metric聚合 二、聚合总结 本文只记录ES聚合基本用法&#xff0c;后续有更复杂的需求可以查看相关书籍&#xff0c;如《Elasticsearch搜索引擎构建入门与实战》 一、数据聚合…

通过 Groovy 实现业务逻辑的动态变更

Groovy 1、需求的提出2、为什么是Groovy3、设计参考1_引入Maven依赖2_GroovyEngineUtils工具类3_GroovyScriptVar类4_脚本规则表设计5_对应的实体类6_数据库访问层7_GroovyExecService通用接口 4、测试5、其他的注意事项6、总结 1、需求的提出 在我们日常的开发过程中&#xf…

【机器学习】智驭未来:探索机器学习在食品生产中的革新之路

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀目录 &#x1f50d;1. 引言&#xff1a;探索机器学习在食品生产中的革新之路&#x1f4d2;2. 机器学习在食品质量控制中的应用&#x1f31e;实…

MySQL之复合查询与内外连接

目录 一、多表查询 二、自连接 三、子查询 四、合并查询 五、表的内连接和外连接 1、内连接 2、外连接 前面我们讲解的mysql表的查询都是对一张表进行查询&#xff0c;即数据的查询都是在某一时刻对一个表进行操作的。而在实际开发中&#xff0c;我们往往还需要对多个表…

15分钟学 Python 第41天:Python 爬虫入门(六)第二篇

Day41&#xff1a;Python爬取猫眼电影网站的电影信息 1. 项目背景 在本项目中&#xff0c;我们将使用 Python 爬虫技术从猫眼电影网站抓取电影信息。猫眼电影是一个知名的电影信息平台&#xff0c;提供了丰富的电影相关数据。通过这个练习&#xff0c;您将深入学习如何抓取动…

Android Compose的基本使用

前言: Compose这个东西呢,好处我没发现,坏处就是学习成本和低版本兼容. 不过,看在官方力推的份儿上,有空就学一下吧. 当初的kotlin,很多人说鸡肋(包括我)!现在不也咔咔用纯kotlin做项目吗?哈哈哈哈. 未来的事情,谁说得清呢? 首先创建一个专用的Compose项目 对没错!看到E…

大数据新视界 --大数据大厂之 从 Druid 和 Kafka 到 Polars:大数据处理工具的传承与创新

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【笔记】数据结构12

文章目录 2013年408应用题41方法一方法二 看到的社区的一个知识总结&#xff0c;这里记录一下。 知识点汇总 2013年408应用题41 解决方法&#xff1a; 方法一 &#xff08;1&#xff09;算法思想 算法的策略是从前向后扫描数组元素&#xff0c;标记出一个可能成为主元素的元…