Loading include/input/KeyCharacterMap.h +14 −4 Original line number Diff line number Diff line Loading @@ -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. */ Loading Loading @@ -144,6 +144,8 @@ public: bool operator==(const KeyCharacterMap& other) const; bool operator!=(const KeyCharacterMap& other) const; KeyCharacterMap(const KeyCharacterMap& other); virtual ~KeyCharacterMap(); Loading Loading @@ -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, Loading @@ -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, Loading @@ -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 Loading libs/input/KeyCharacterMap.cpp +110 −26 Original line number Diff line number Diff line Loading @@ -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++) { Loading @@ -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()) { Loading Loading @@ -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; Loading @@ -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( Loading @@ -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); Loading @@ -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 { Loading Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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); Loading @@ -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__ Loading libs/input/tests/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ cc_test { "libui", "libutils", ], data: ["data/*.kcm"], test_suites: ["device-tests"], } Loading @@ -59,5 +60,5 @@ cc_library_static { "libbinder", "libui", "libbase", ] ], } libs/input/tests/InputDevice_test.cpp +50 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <input/InputDevice.h> #include <input/KeyLayoutMap.h> #include <input/Keyboard.h> #include "android-base/file.h" namespace android { Loading Loading @@ -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 libs/input/tests/data/english_us.kcm 0 → 100644 +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
include/input/KeyCharacterMap.h +14 −4 Original line number Diff line number Diff line Loading @@ -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. */ Loading Loading @@ -144,6 +144,8 @@ public: bool operator==(const KeyCharacterMap& other) const; bool operator!=(const KeyCharacterMap& other) const; KeyCharacterMap(const KeyCharacterMap& other); virtual ~KeyCharacterMap(); Loading Loading @@ -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, Loading @@ -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, Loading @@ -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 Loading
libs/input/KeyCharacterMap.cpp +110 −26 Original line number Diff line number Diff line Loading @@ -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++) { Loading @@ -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()) { Loading Loading @@ -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; Loading @@ -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( Loading @@ -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); Loading @@ -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 { Loading Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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); Loading @@ -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__ Loading
libs/input/tests/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ cc_test { "libui", "libutils", ], data: ["data/*.kcm"], test_suites: ["device-tests"], } Loading @@ -59,5 +60,5 @@ cc_library_static { "libbinder", "libui", "libbase", ] ], }
libs/input/tests/InputDevice_test.cpp +50 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <input/InputDevice.h> #include <input/KeyLayoutMap.h> #include <input/Keyboard.h> #include "android-base/file.h" namespace android { Loading Loading @@ -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
libs/input/tests/data/english_us.kcm 0 → 100644 +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