summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/input/KeyCharacterMap.h8
-rw-r--r--include/input/Keyboard.h7
-rw-r--r--libs/input/KeyCharacterMap.cpp108
-rw-r--r--libs/input/Keyboard.cpp5
-rw-r--r--services/inputflinger/EventHub.cpp30
-rw-r--r--services/inputflinger/EventHub.h10
-rw-r--r--services/inputflinger/InputReader.cpp34
-rw-r--r--services/inputflinger/InputReader.h3
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp8
9 files changed, 173 insertions, 40 deletions
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index e70666a..3f0914b 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -124,6 +124,11 @@ public:
* the mapping in some way. */
status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const;
+ /* Tries to find a replacement key code for a given key code and meta state
+ * in character map. */
+ void tryRemapKey(int32_t scanCode, int32_t metaState,
+ int32_t* outKeyCode, int32_t* outMetaState) const;
+
#if HAVE_ANDROID_OS
/* Reads a key map from a parcel. */
static sp<KeyCharacterMap> readFromParcel(Parcel* parcel);
@@ -151,6 +156,9 @@ private:
/* The fallback keycode if the key is not handled. */
int32_t fallbackKeyCode;
+
+ /* The replacement keycode if the key has to be replaced outright. */
+ int32_t replacementKeyCode;
};
struct Key {
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index 519bb22..d4903e9 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -88,6 +88,13 @@ extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentif
extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
/**
+ * Normalizes the meta state such that if either the left or right modifier
+ * meta state bits are set then the result will also include the universal
+ * bit for that modifier.
+ */
+extern int32_t normalizeMetaState(int32_t oldMetaState);
+
+/**
* Returns true if a key is a meta key like ALT or CAPS_LOCK.
*/
extern bool isMetaKey(int32_t keyCode);
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index b03e01e..df3f0dd 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -332,33 +332,75 @@ status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* o
if (usageCode) {
ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
if (index >= 0) {
+ *outKeyCode = mKeysByUsageCode.valueAt(index);
#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
- scanCode, usageCode, *outKeyCode);
+ ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
+ scanCode, usageCode, *outKeyCode);
#endif
- *outKeyCode = mKeysByUsageCode.valueAt(index);
return OK;
}
}
if (scanCode) {
ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
if (index >= 0) {
+ *outKeyCode = mKeysByScanCode.valueAt(index);
#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
- scanCode, usageCode, *outKeyCode);
+ ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
+ scanCode, usageCode, *outKeyCode);
#endif
- *outKeyCode = mKeysByScanCode.valueAt(index);
return OK;
}
}
#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
+ ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
#endif
*outKeyCode = AKEYCODE_UNKNOWN;
return NAME_NOT_FOUND;
}
+void KeyCharacterMap::tryRemapKey(int32_t keyCode, int32_t metaState,
+ int32_t *outKeyCode, int32_t *outMetaState) const {
+ *outKeyCode = keyCode;
+ *outMetaState = metaState;
+
+ const Key* key;
+ const Behavior* behavior;
+ if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+ if (behavior->replacementKeyCode) {
+ *outKeyCode = behavior->replacementKeyCode;
+ int32_t newMetaState = metaState & ~behavior->metaState;
+ // Reset dependent meta states.
+ if (behavior->metaState & AMETA_ALT_ON) {
+ newMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
+ }
+ if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
+ newMetaState &= ~AMETA_ALT_ON;
+ }
+ if (behavior->metaState & AMETA_CTRL_ON) {
+ newMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
+ }
+ if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
+ newMetaState &= ~AMETA_CTRL_ON;
+ }
+ if (behavior->metaState & AMETA_SHIFT_ON) {
+ newMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
+ }
+ if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
+ newMetaState &= ~AMETA_SHIFT_ON;
+ }
+ // ... and put universal bits back if needed
+ *outMetaState = normalizeMetaState(newMetaState);
+ }
+ }
+
+#if DEBUG_MAPPING
+ ALOGD("tryRemapKey: keyCode=%d, metaState=0x%08x ~ "
+ "replacement keyCode=%d, replacement metaState=0x%08x.",
+ keyCode, metaState, *outKeyCode, *outMetaState);
+#endif
+}
+
bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
ssize_t index = mKeys.indexOfKey(keyCode);
if (index >= 0) {
@@ -584,6 +626,7 @@ sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
int32_t metaState = parcel->readInt32();
char16_t character = parcel->readInt32();
int32_t fallbackKeyCode = parcel->readInt32();
+ int32_t replacementKeyCode = parcel->readInt32();
if (parcel->errorCheck()) {
return NULL;
}
@@ -592,6 +635,7 @@ sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
behavior->metaState = metaState;
behavior->character = character;
behavior->fallbackKeyCode = fallbackKeyCode;
+ behavior->replacementKeyCode = replacementKeyCode;
if (lastBehavior) {
lastBehavior->next = behavior;
} else {
@@ -624,6 +668,7 @@ void KeyCharacterMap::writeToParcel(Parcel* parcel) const {
parcel->writeInt32(behavior->metaState);
parcel->writeInt32(behavior->character);
parcel->writeInt32(behavior->fallbackKeyCode);
+ parcel->writeInt32(behavior->replacementKeyCode);
}
parcel->writeInt32(0);
}
@@ -655,13 +700,14 @@ KeyCharacterMap::Key::~Key() {
// --- KeyCharacterMap::Behavior ---
KeyCharacterMap::Behavior::Behavior() :
- next(NULL), metaState(0), character(0), fallbackKeyCode(0) {
+ next(NULL), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
}
KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
next(other.next ? new Behavior(*other.next) : NULL),
metaState(other.metaState), character(other.character),
- fallbackKeyCode(other.fallbackKeyCode) {
+ fallbackKeyCode(other.fallbackKeyCode),
+ replacementKeyCode(other.replacementKeyCode) {
}
@@ -923,6 +969,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
Behavior behavior;
bool haveCharacter = false;
bool haveFallback = false;
+ bool haveReplacement = false;
do {
char ch = mTokenizer->peekChar();
@@ -939,6 +986,11 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
mTokenizer->getLocation().string());
return BAD_VALUE;
}
+ if (haveReplacement) {
+ ALOGE("%s: Cannot combine character literal with replace action.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
behavior.character = character;
haveCharacter = true;
} else {
@@ -949,6 +1001,11 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
mTokenizer->getLocation().string());
return BAD_VALUE;
}
+ if (haveReplacement) {
+ ALOGE("%s: Cannot combine 'none' with replace action.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
haveCharacter = true;
} else if (token == "fallback") {
mTokenizer->skipDelimiters(WHITESPACE);
@@ -960,13 +1017,36 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
token.string());
return BAD_VALUE;
}
- if (haveFallback) {
- ALOGE("%s: Cannot combine multiple fallback key codes.",
+ if (haveFallback || haveReplacement) {
+ ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
behavior.fallbackKeyCode = keyCode;
haveFallback = true;
+ } else if (token == "replace") {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ token = mTokenizer->nextToken(WHITESPACE);
+ int32_t keyCode = getKeyCodeByLabel(token.string());
+ if (!keyCode) {
+ ALOGE("%s: Invalid key code label for replace, got '%s'.",
+ mTokenizer->getLocation().string(),
+ token.string());
+ return BAD_VALUE;
+ }
+ if (haveCharacter) {
+ ALOGE("%s: Cannot combine character literal with replace action.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ if (haveFallback || haveReplacement) {
+ ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ behavior.replacementKeyCode = keyCode;
+ haveReplacement = true;
+
} else {
ALOGE("%s: Expected a key behavior after ':'.",
mTokenizer->getLocation().string());
@@ -1016,8 +1096,10 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() {
newBehavior->next = key->firstBehavior;
key->firstBehavior = newBehavior;
#if DEBUG_PARSER
- ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode,
- newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode);
+ ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
+ mKeyCode,
+ newBehavior->metaState, newBehavior->character,
+ newBehavior->fallbackKeyCode, newBehavior->replacementKeyCode);
#endif
break;
}
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index f4d9507..9a01395 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -176,6 +176,11 @@ static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaSta
~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
}
+ return normalizeMetaState(newMetaState);
+}
+
+int32_t normalizeMetaState(int32_t oldMetaState) {
+ int32_t newMetaState = oldMetaState;
if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
newMetaState |= AMETA_ALT_ON;
}
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 6b60c7c..5859606 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -438,10 +438,12 @@ bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
return false;
}
-status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
- int32_t* outKeycode, uint32_t* outFlags) const {
+status_t EventHub::mapKey(int32_t deviceId,
+ int32_t scanCode, int32_t usageCode, int32_t metaState,
+ int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
+ status_t status = NAME_NOT_FOUND;
if (device) {
// Check the key character map first.
@@ -449,22 +451,34 @@ status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
if (kcm != NULL) {
if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
*outFlags = 0;
- return NO_ERROR;
+ status = NO_ERROR;
}
}
// Check the key layout next.
- if (device->keyMap.haveKeyLayout()) {
+ if (status != NO_ERROR && device->keyMap.haveKeyLayout()) {
if (!device->keyMap.keyLayoutMap->mapKey(
scanCode, usageCode, outKeycode, outFlags)) {
- return NO_ERROR;
+ status = NO_ERROR;
+ }
+ }
+
+ if (status == NO_ERROR) {
+ if (kcm != NULL) {
+ kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState);
+ } else {
+ *outMetaState = metaState;
}
}
}
- *outKeycode = 0;
- *outFlags = 0;
- return NAME_NOT_FOUND;
+ if (status != NO_ERROR) {
+ *outKeycode = 0;
+ *outFlags = 0;
+ *outMetaState = metaState;
+ }
+
+ return status;
}
status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const {
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 3ec4910..0f94c77 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -197,8 +197,9 @@ public:
virtual bool hasInputProperty(int32_t deviceId, int property) const = 0;
- virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
- int32_t* outKeycode, uint32_t* outFlags) const = 0;
+ virtual status_t mapKey(int32_t deviceId,
+ int32_t scanCode, int32_t usageCode, int32_t metaState,
+ int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const = 0;
virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
AxisInfo* outAxisInfo) const = 0;
@@ -285,8 +286,9 @@ public:
virtual bool hasInputProperty(int32_t deviceId, int property) const;
- virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
- int32_t* outKeycode, uint32_t* outFlags) const;
+ virtual status_t mapKey(int32_t deviceId,
+ int32_t scanCode, int32_t usageCode, int32_t metaState,
+ int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const;
virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
AxisInfo* outAxisInfo) const;
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 36095bf..b2cbfe8 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2177,13 +2177,7 @@ void KeyboardInputMapper::process(const RawEvent* rawEvent) {
mCurrentHidUsage = 0;
if (isKeyboardOrGamepadKey(scanCode)) {
- int32_t keyCode;
- uint32_t flags;
- if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {
- keyCode = AKEYCODE_UNKNOWN;
- flags = 0;
- }
- processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
+ processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
}
break;
}
@@ -2208,8 +2202,18 @@ bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
|| (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
}
-void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
- int32_t scanCode, uint32_t policyFlags) {
+void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
+ int32_t usageCode) {
+ int32_t keyCode;
+ int32_t keyMetaState;
+ uint32_t policyFlags;
+
+ if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
+ &keyCode, &keyMetaState, &policyFlags)) {
+ keyCode = AKEYCODE_UNKNOWN;
+ keyMetaState = mMetaState;
+ policyFlags = 0;
+ }
if (down) {
// Rotate key codes according to orientation if needed.
@@ -2262,6 +2266,12 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
if (metaStateChanged) {
mMetaState = newMetaState;
updateLedState(false);
+
+ // If global meta state changed send it along with the key.
+ // If it has not changed then we'll use what keymap gave us,
+ // since key replacement logic might temporarily reset a few
+ // meta bits for given key.
+ keyMetaState = newMetaState;
}
nsecs_t downTime = mDownTime;
@@ -2289,7 +2299,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
+ AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
getListener()->notifyKey(&args);
}
@@ -3543,8 +3553,10 @@ void TouchInputMapper::configureVirtualKeys() {
virtualKey.scanCode = virtualKeyDefinition.scanCode;
int32_t keyCode;
+ int32_t dummyKeyMetaState;
uint32_t flags;
- if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, &keyCode, &flags)) {
+ if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, 0,
+ &keyCode, &dummyKeyMetaState, &flags)) {
ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
virtualKey.scanCode);
mVirtualKeys.pop(); // drop the key
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 7cb4680..30c84b1 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -1154,8 +1154,7 @@ private:
bool isKeyboardOrGamepadKey(int32_t scanCode);
- void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
- uint32_t policyFlags);
+ void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode);
ssize_t findKeyDown(int32_t scanCode);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index f34b810..42bc865 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -518,8 +518,9 @@ private:
return false;
}
- virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
- int32_t* outKeycode, uint32_t* outFlags) const {
+ virtual status_t mapKey(int32_t deviceId,
+ int32_t scanCode, int32_t usageCode, int32_t metaState,
+ int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const {
Device* device = getDevice(deviceId);
if (device) {
const KeyInfo* key = getKey(device, scanCode, usageCode);
@@ -530,6 +531,9 @@ private:
if (outFlags) {
*outFlags = key->flags;
}
+ if (outMetaState) {
+ *outMetaState = metaState;
+ }
return OK;
}
}