summaryrefslogtreecommitdiff
path: root/libs/androidfw/KeyCharacterMap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/androidfw/KeyCharacterMap.cpp')
-rw-r--r--libs/androidfw/KeyCharacterMap.cpp70
1 files changed, 62 insertions, 8 deletions
diff --git a/libs/androidfw/KeyCharacterMap.cpp b/libs/androidfw/KeyCharacterMap.cpp
index c8f94390e4bf..2dc7507f352d 100644
--- a/libs/androidfw/KeyCharacterMap.cpp
+++ b/libs/androidfw/KeyCharacterMap.cpp
@@ -372,7 +372,7 @@ bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
if (getKey(keyCode, &key)) {
const Behavior* behavior = key->firstBehavior;
while (behavior) {
- if ((behavior->metaState & metaState) == behavior->metaState) {
+ if (matchesMetaState(metaState, behavior->metaState)) {
*outKey = key;
*outBehavior = behavior;
return true;
@@ -383,6 +383,37 @@ bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
return false;
}
+bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
+ // Behavior must have at least the set of meta states specified.
+ // And if the key event has CTRL, ALT or META then the behavior must exactly
+ // match those, taking into account that a behavior can specify that it handles
+ // one, both or either of a left/right modifier pair.
+ if ((eventMetaState & behaviorMetaState) == behaviorMetaState) {
+ const int32_t EXACT_META_STATES =
+ AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON
+ | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON
+ | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON;
+ int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES;
+ if (behaviorMetaState & AMETA_CTRL_ON) {
+ unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
+ } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
+ unmatchedMetaState &= ~AMETA_CTRL_ON;
+ }
+ if (behaviorMetaState & AMETA_ALT_ON) {
+ unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
+ } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
+ unmatchedMetaState &= ~AMETA_ALT_ON;
+ }
+ if (behaviorMetaState & AMETA_META_ON) {
+ unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
+ } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
+ unmatchedMetaState &= ~AMETA_META_ON;
+ }
+ return !unmatchedMetaState;
+ }
+ return false;
+}
+
bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
if (!ch) {
return false;
@@ -699,12 +730,13 @@ status_t KeyCharacterMap::Parser::parse() {
return BAD_VALUE;
}
+ if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
+ ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
if (mFormat == FORMAT_BASE) {
- if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
- ALOGE("%s: Base keyboard layout missing required keyboard 'type' declaration.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
if (mMap->mType == KEYBOARD_TYPE_OVERLAY) {
ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
mTokenizer->getLocation().string());
@@ -840,10 +872,11 @@ status_t KeyCharacterMap::Parser::parseKey() {
}
status_t KeyCharacterMap::Parser::parseKeyProperty() {
+ Key* key = mMap->mKeys.valueFor(mKeyCode);
String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
if (token == "}") {
mState = STATE_TOP;
- return NO_ERROR;
+ return finishKey(key);
}
Vector<Property> properties;
@@ -943,7 +976,6 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
} while (!mTokenizer->isEol());
// Add the behavior.
- Key* key = mMap->mKeys.valueFor(mKeyCode);
for (size_t i = 0; i < properties.size(); i++) {
const Property& property = properties.itemAt(i);
switch (property.property) {
@@ -992,6 +1024,28 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
return NO_ERROR;
}
+status_t KeyCharacterMap::Parser::finishKey(Key* key) {
+ // Fill in default number property.
+ if (!key->number) {
+ char16_t digit = 0;
+ char16_t symbol = 0;
+ for (Behavior* b = key->firstBehavior; b; b = b->next) {
+ char16_t ch = b->character;
+ if (ch) {
+ if (ch >= '0' && ch <= '9') {
+ digit = ch;
+ } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*'
+ || ch == '-' || ch == '+' || ch == ',' || ch == '.'
+ || ch == '\'' || ch == ':' || ch == ';' || ch == '/') {
+ symbol = ch;
+ }
+ }
+ }
+ key->number = digit ? digit : symbol;
+ }
+ return NO_ERROR;
+}
+
status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
if (token == "base") {
*outMetaState = 0;