Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f28d23f authored by Philip Junker's avatar Philip Junker Committed by Android (Google) Code Review
Browse files

Merge "Fix KeyCharacterMap overlays by reloading base overlay before applying...

Merge "Fix KeyCharacterMap overlays by reloading base overlay before applying another overlay." into sc-v2-dev
parents b6f84790 b60596f6
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ public:

    const std::string getLoadFileName() const;

    /* Combines this key character map with an overlay. */
    /* Combines this key character map with the provided overlay. */
    void combine(const KeyCharacterMap& overlay);

    /* Gets the keyboard type. */
@@ -144,6 +144,8 @@ public:

    bool operator==(const KeyCharacterMap& other) const;

    bool operator!=(const KeyCharacterMap& other) const;

    KeyCharacterMap(const KeyCharacterMap& other);

    virtual ~KeyCharacterMap();
@@ -230,11 +232,12 @@ private:
    KeyedVector<int32_t, Key*> mKeys;
    KeyboardType mType;
    std::string mLoadFileName;
    bool mLayoutOverlayApplied;

    KeyedVector<int32_t, int32_t> mKeysByScanCode;
    KeyedVector<int32_t, int32_t> mKeysByUsageCode;

    KeyCharacterMap();
    KeyCharacterMap(const std::string& filename);

    bool getKey(int32_t keyCode, const Key** outKey) const;
    bool getKeyBehavior(int32_t keyCode, int32_t metaState,
@@ -243,8 +246,6 @@ private:

    bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;

    static base::Result<std::shared_ptr<KeyCharacterMap>> load(Tokenizer* tokenizer, Format format);

    static void addKey(Vector<KeyEvent>& outEvents,
            int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time);
    static void addMetaKeys(Vector<KeyEvent>& outEvents,
@@ -264,6 +265,15 @@ private:
            int32_t deviceId, int32_t metaState, nsecs_t time,
            int32_t keyCode, int32_t keyMetaState,
            int32_t* currentMetaState);

    /* Clears all data stored in this key character map */
    void clear();

    /* Loads the KeyCharacterMap provided by the tokenizer into this instance. */
    status_t load(Tokenizer* tokenizer, Format format);

    /* Reloads the data from mLoadFileName and unapplies any overlay. */
    status_t reloadBaseFromFile();
};

} // namespace android
+110 −26
Original line number Diff line number Diff line
@@ -86,10 +86,13 @@ static String8 toString(const char16_t* chars, size_t numChars) {

// --- KeyCharacterMap ---

KeyCharacterMap::KeyCharacterMap() : mType(KeyboardType::UNKNOWN) {}
KeyCharacterMap::KeyCharacterMap(const std::string& filename)
      : mType(KeyboardType::UNKNOWN), mLoadFileName(filename) {}

KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other)
      : mType(other.mType),
        mLoadFileName(other.mLoadFileName),
        mLayoutOverlayApplied(other.mLayoutOverlayApplied),
        mKeysByScanCode(other.mKeysByScanCode),
        mKeysByUsageCode(other.mKeysByUsageCode) {
    for (size_t i = 0; i < other.mKeys.size(); i++) {
@@ -98,16 +101,19 @@ KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other)
}

KeyCharacterMap::~KeyCharacterMap() {
    for (size_t i = 0; i < mKeys.size(); i++) {
        Key* key = mKeys.editValueAt(i);
        delete key;
    }
    clear();
}

bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const {
    if (mType != other.mType) {
        return false;
    }
    if (mLoadFileName != other.mLoadFileName) {
        return false;
    }
    if (mLayoutOverlayApplied != other.mLayoutOverlayApplied) {
        return false;
    }
    if (mKeys.size() != other.mKeys.size() ||
        mKeysByScanCode.size() != other.mKeysByScanCode.size() ||
        mKeysByUsageCode.size() != other.mKeysByUsageCode.size()) {
@@ -146,6 +152,10 @@ bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const {
    return true;
}

bool KeyCharacterMap::operator!=(const KeyCharacterMap& other) const {
    return !(*this == other);
}

base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
                                                                     Format format) {
    Tokenizer* tokenizer;
@@ -153,12 +163,18 @@ base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::
    if (status) {
        return Errorf("Error {} opening key character map file {}.", status, filename.c_str());
    }
    std::shared_ptr<KeyCharacterMap> map =
            std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
    if (!map.get()) {
        ALOGE("Error allocating key character map.");
        return Errorf("Error allocating key character map.");
    }
    std::unique_ptr<Tokenizer> t(tokenizer);
    auto ret = load(t.get(), format);
    if (ret.ok()) {
        (*ret)->mLoadFileName = filename;
    status = map->load(t.get(), format);
    if (status == OK) {
        return map;
    }
    return ret;
    return Errorf("Load KeyCharacterMap failed {}.", status);
}

base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents(
@@ -169,40 +185,67 @@ base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::loadContents(
        ALOGE("Error %d opening key character map.", status);
        return Errorf("Error {} opening key character map.", status);
    }
    std::shared_ptr<KeyCharacterMap> map =
            std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(filename));
    if (!map.get()) {
        ALOGE("Error allocating key character map.");
        return Errorf("Error allocating key character map.");
    }
    std::unique_ptr<Tokenizer> t(tokenizer);
    auto ret = load(t.get(), format);
    if (ret.ok()) {
        (*ret)->mLoadFileName = filename;
    status = map->load(t.get(), format);
    if (status == OK) {
        return map;
    }
    return ret;
    return Errorf("Load KeyCharacterMap failed {}.", status);
}

base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(Tokenizer* tokenizer,
                                                                     Format format) {
status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) {
    status_t status = OK;
    std::shared_ptr<KeyCharacterMap> map = std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap());
    if (!map.get()) {
        ALOGE("Error allocating key character map.");
        return Errorf("Error allocating key character map.");
    }
#if DEBUG_PARSER_PERFORMANCE
    nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
    Parser parser(map.get(), tokenizer, format);
    Parser parser(this, tokenizer, format);
    status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
    nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
    ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
          tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0);
#endif
    if (status == OK) {
        return map;
    if (status != OK) {
        ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str());
    }
    return status;
}

    return Errorf("Load KeyCharacterMap failed {}.", status);
void KeyCharacterMap::clear() {
    mKeysByScanCode.clear();
    mKeysByUsageCode.clear();
    for (size_t i = 0; i < mKeys.size(); i++) {
        Key* key = mKeys.editValueAt(i);
        delete key;
    }
    mKeys.clear();
    mLayoutOverlayApplied = false;
    mType = KeyboardType::UNKNOWN;
}

status_t KeyCharacterMap::reloadBaseFromFile() {
    clear();
    Tokenizer* tokenizer;
    status_t status = Tokenizer::open(String8(mLoadFileName.c_str()), &tokenizer);
    if (status) {
        ALOGE("Error %s opening key character map file %s.", statusToString(status).c_str(),
              mLoadFileName.c_str());
        return status;
    }
    std::unique_ptr<Tokenizer> t(tokenizer);
    return load(t.get(), KeyCharacterMap::Format::BASE);
}

void KeyCharacterMap::combine(const KeyCharacterMap& overlay) {
    if (mLayoutOverlayApplied) {
        reloadBaseFromFile();
    }
    for (size_t i = 0; i < overlay.mKeys.size(); i++) {
        int32_t keyCode = overlay.mKeys.keyAt(i);
        Key* key = overlay.mKeys.valueAt(i);
@@ -224,7 +267,7 @@ void KeyCharacterMap::combine(const KeyCharacterMap& overlay) {
        mKeysByUsageCode.replaceValueFor(overlay.mKeysByUsageCode.keyAt(i),
                                         overlay.mKeysByUsageCode.valueAt(i));
    }
    mLoadFileName = overlay.mLoadFileName;
    mLayoutOverlayApplied = true;
}

KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const {
@@ -636,8 +679,11 @@ std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel)
        ALOGE("%s: Null parcel", __func__);
        return nullptr;
    }
    std::shared_ptr<KeyCharacterMap> map = std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap());
    std::string loadFileName = parcel->readCString();
    std::shared_ptr<KeyCharacterMap> map =
            std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap(loadFileName));
    map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
    map->mLayoutOverlayApplied = parcel->readBool();
    size_t numKeys = parcel->readInt32();
    if (parcel->errorCheck()) {
        return nullptr;
@@ -687,6 +733,30 @@ std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel)
            return nullptr;
        }
    }
    size_t numKeysByScanCode = parcel->readInt32();
    if (parcel->errorCheck()) {
        return nullptr;
    }
    for (size_t i = 0; i < numKeysByScanCode; i++) {
        int32_t key = parcel->readInt32();
        int32_t value = parcel->readInt32();
        map->mKeysByScanCode.add(key, value);
        if (parcel->errorCheck()) {
            return nullptr;
        }
    }
    size_t numKeysByUsageCode = parcel->readInt32();
    if (parcel->errorCheck()) {
        return nullptr;
    }
    for (size_t i = 0; i < numKeysByUsageCode; i++) {
        int32_t key = parcel->readInt32();
        int32_t value = parcel->readInt32();
        map->mKeysByUsageCode.add(key, value);
        if (parcel->errorCheck()) {
            return nullptr;
        }
    }
    return map;
}

@@ -695,7 +765,9 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
        ALOGE("%s: Null parcel", __func__);
        return;
    }
    parcel->writeCString(mLoadFileName.c_str());
    parcel->writeInt32(static_cast<int32_t>(mType));
    parcel->writeBool(mLayoutOverlayApplied);

    size_t numKeys = mKeys.size();
    parcel->writeInt32(numKeys);
@@ -715,6 +787,18 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
        }
        parcel->writeInt32(0);
    }
    size_t numKeysByScanCode = mKeysByScanCode.size();
    parcel->writeInt32(numKeysByScanCode);
    for (size_t i = 0; i < numKeysByScanCode; i++) {
        parcel->writeInt32(mKeysByScanCode.keyAt(i));
        parcel->writeInt32(mKeysByScanCode.valueAt(i));
    }
    size_t numKeysByUsageCode = mKeysByUsageCode.size();
    parcel->writeInt32(numKeysByUsageCode);
    for (size_t i = 0; i < numKeysByUsageCode; i++) {
        parcel->writeInt32(mKeysByUsageCode.keyAt(i));
        parcel->writeInt32(mKeysByUsageCode.valueAt(i));
    }
}
#endif // __linux__

+2 −1
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ cc_test {
        "libui",
        "libutils",
    ],
    data: ["data/*.kcm"],
    test_suites: ["device-tests"],
}

@@ -59,5 +60,5 @@ cc_library_static {
        "libbinder",
        "libui",
        "libbase",
    ]
    ],
}
+50 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <input/InputDevice.h>
#include <input/KeyLayoutMap.h>
#include <input/Keyboard.h>
#include "android-base/file.h"

namespace android {

@@ -82,4 +83,53 @@ TEST_F(InputDeviceKeyMapTest, keyCharacterMapParcelingTest) {
    ASSERT_EQ(*map, *mKeyMap.keyCharacterMap);
}

TEST_F(InputDeviceKeyMapTest, keyCharacterMapWithOverlayParcelingTest) {
    Parcel parcel;
    std::string overlayPath = base::GetExecutableDirectory() + "/data/german.kcm";
    base::Result<std::shared_ptr<KeyCharacterMap>> overlay =
            KeyCharacterMap::load(overlayPath, KeyCharacterMap::Format::OVERLAY);
    ASSERT_TRUE(overlay.ok()) << "Cannot load KeyCharacterMap at " << overlayPath;
    mKeyMap.keyCharacterMap->combine(*overlay->get());
    mKeyMap.keyCharacterMap->writeToParcel(&parcel);
    parcel.setDataPosition(0);
    std::shared_ptr<KeyCharacterMap> map = KeyCharacterMap::readFromParcel(&parcel);
    ASSERT_EQ(*map, *mKeyMap.keyCharacterMap);
}

TEST_F(InputDeviceKeyMapTest, keyCharacteMapApplyMultipleOverlaysTest) {
    std::string frenchOverlayPath = base::GetExecutableDirectory() + "/data/french.kcm";
    std::string englishOverlayPath = base::GetExecutableDirectory() + "/data/english_us.kcm";
    std::string germanOverlayPath = base::GetExecutableDirectory() + "/data/german.kcm";
    base::Result<std::shared_ptr<KeyCharacterMap>> frenchOverlay =
            KeyCharacterMap::load(frenchOverlayPath, KeyCharacterMap::Format::OVERLAY);
    ASSERT_TRUE(frenchOverlay.ok()) << "Cannot load KeyCharacterMap at " << frenchOverlayPath;
    base::Result<std::shared_ptr<KeyCharacterMap>> englishOverlay =
            KeyCharacterMap::load(englishOverlayPath, KeyCharacterMap::Format::OVERLAY);
    ASSERT_TRUE(englishOverlay.ok()) << "Cannot load KeyCharacterMap at " << englishOverlayPath;
    base::Result<std::shared_ptr<KeyCharacterMap>> germanOverlay =
            KeyCharacterMap::load(germanOverlayPath, KeyCharacterMap::Format::OVERLAY);
    ASSERT_TRUE(germanOverlay.ok()) << "Cannot load KeyCharacterMap at " << germanOverlayPath;

    // Apply the French overlay
    mKeyMap.keyCharacterMap->combine(*frenchOverlay->get());
    // Copy the result for later
    std::shared_ptr<KeyCharacterMap> frenchOverlaidKeyCharacterMap =
            std::make_shared<KeyCharacterMap>(*mKeyMap.keyCharacterMap);

    // Apply the English overlay
    mKeyMap.keyCharacterMap->combine(*englishOverlay->get());
    // Verify that the result is different from the French overlay result
    ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);

    // Apply the German overlay
    mKeyMap.keyCharacterMap->combine(*germanOverlay->get());
    // Verify that the result is different from the French overlay result
    ASSERT_NE(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);

    // Apply the French overlay
    mKeyMap.keyCharacterMap->combine(*frenchOverlay->get());
    // Verify that the result is the same like after applying it initially
    ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap);
}

} // namespace android
+311 −0
Original line number Diff line number Diff line
# Copyright (C) 2021 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#
# English (US) keyboard layout.
# Unlike the default (generic) keyboard layout, English (US) does not contain any
# special ALT characters.
#

type OVERLAY

### ROW 1

key GRAVE {
    label:                              '`'
    base:                               '`'
    shift:                              '~'
}

key 1 {
    label:                              '1'
    base:                               '1'
    shift:                              '!'
}

key 2 {
    label:                              '2'
    base:                               '2'
    shift:                              '@'
}

key 3 {
    label:                              '3'
    base:                               '3'
    shift:                              '#'
}

key 4 {
    label:                              '4'
    base:                               '4'
    shift:                              '$'
}

key 5 {
    label:                              '5'
    base:                               '5'
    shift:                              '%'
}

key 6 {
    label:                              '6'
    base:                               '6'
    shift:                              '^'
}

key 7 {
    label:                              '7'
    base:                               '7'
    shift:                              '&'
}

key 8 {
    label:                              '8'
    base:                               '8'
    shift:                              '*'
}

key 9 {
    label:                              '9'
    base:                               '9'
    shift:                              '('
}

key 0 {
    label:                              '0'
    base:                               '0'
    shift:                              ')'
}

key MINUS {
    label:                              '-'
    base:                               '-'
    shift:                              '_'
}

key EQUALS {
    label:                              '='
    base:                               '='
    shift:                              '+'
}

### ROW 2

key Q {
    label:                              'Q'
    base:                               'q'
    shift, capslock:                    'Q'
}

key W {
    label:                              'W'
    base:                               'w'
    shift, capslock:                    'W'
}

key E {
    label:                              'E'
    base:                               'e'
    shift, capslock:                    'E'
}

key R {
    label:                              'R'
    base:                               'r'
    shift, capslock:                    'R'
}

key T {
    label:                              'T'
    base:                               't'
    shift, capslock:                    'T'
}

key Y {
    label:                              'Y'
    base:                               'y'
    shift, capslock:                    'Y'
}

key U {
    label:                              'U'
    base:                               'u'
    shift, capslock:                    'U'
}

key I {
    label:                              'I'
    base:                               'i'
    shift, capslock:                    'I'
}

key O {
    label:                              'O'
    base:                               'o'
    shift, capslock:                    'O'
}

key P {
    label:                              'P'
    base:                               'p'
    shift, capslock:                    'P'
}

key LEFT_BRACKET {
    label:                              '['
    base:                               '['
    shift:                              '{'
}

key RIGHT_BRACKET {
    label:                              ']'
    base:                               ']'
    shift:                              '}'
}

key BACKSLASH {
    label:                              '\\'
    base:                               '\\'
    shift:                              '|'
}

### ROW 3

key A {
    label:                              'A'
    base:                               'a'
    shift, capslock:                    'A'
}

key S {
    label:                              'S'
    base:                               's'
    shift, capslock:                    'S'
}

key D {
    label:                              'D'
    base:                               'd'
    shift, capslock:                    'D'
}

key F {
    label:                              'F'
    base:                               'f'
    shift, capslock:                    'F'
}

key G {
    label:                              'G'
    base:                               'g'
    shift, capslock:                    'G'
}

key H {
    label:                              'H'
    base:                               'h'
    shift, capslock:                    'H'
}

key J {
    label:                              'J'
    base:                               'j'
    shift, capslock:                    'J'
}

key K {
    label:                              'K'
    base:                               'k'
    shift, capslock:                    'K'
}

key L {
    label:                              'L'
    base:                               'l'
    shift, capslock:                    'L'
}

key SEMICOLON {
    label:                              ';'
    base:                               ';'
    shift:                              ':'
}

key APOSTROPHE {
    label:                              '\''
    base:                               '\''
    shift:                              '"'
}

### ROW 4

key Z {
    label:                              'Z'
    base:                               'z'
    shift, capslock:                    'Z'
}

key X {
    label:                              'X'
    base:                               'x'
    shift, capslock:                    'X'
}

key C {
    label:                              'C'
    base:                               'c'
    shift, capslock:                    'C'
}

key V {
    label:                              'V'
    base:                               'v'
    shift, capslock:                    'V'
}

key B {
    label:                              'B'
    base:                               'b'
    shift, capslock:                    'B'
}

key N {
    label:                              'N'
    base:                               'n'
    shift, capslock:                    'N'
}

key M {
    label:                              'M'
    base:                               'm'
    shift, capslock:                    'M'
}

key COMMA {
    label:                              ','
    base:                               ','
    shift:                              '<'
}

key PERIOD {
    label:                              '.'
    base:                               '.'
    shift:                              '>'
}

key SLASH {
    label:                              '/'
    base:                               '/'
    shift:                              '?'
}
 No newline at end of file
Loading