Inputflinger: hook up key event replacement processing

Add handling of "replacement" key events in InputReader and EventHub by
consulting device's character key map (if exists) for presence of
replacement key code for given get code and meta state combination,
before passing it to InputDispatcher.

This enables defining special keys, such as ESC, on keyboards lacking
enough physical keys, via combination of normal keys and modifiers, for
example AltR + 1 => ESC.

Bug: 24504154

Change-Id: I7e36104808bedcf724436c1fbb63d37c35cca8af
This commit is contained in:
Dmitry Torokhov 2015-09-24 13:13:55 -07:00
parent 115f93eeeb
commit 0faaa0bd7a
5 changed files with 58 additions and 27 deletions

View File

@ -438,10 +438,12 @@ bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
return false; return false;
} }
status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, status_t EventHub::mapKey(int32_t deviceId,
int32_t* outKeycode, uint32_t* outFlags) const { int32_t scanCode, int32_t usageCode, int32_t metaState,
int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
AutoMutex _l(mLock); AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId); Device* device = getDeviceLocked(deviceId);
status_t status = NAME_NOT_FOUND;
if (device) { if (device) {
// Check the key character map first. // 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 != NULL) {
if (!kcm->mapKey(scanCode, usageCode, outKeycode)) { if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
*outFlags = 0; *outFlags = 0;
return NO_ERROR; status = NO_ERROR;
} }
} }
// Check the key layout next. // Check the key layout next.
if (device->keyMap.haveKeyLayout()) { if (status != NO_ERROR && device->keyMap.haveKeyLayout()) {
if (!device->keyMap.keyLayoutMap->mapKey( if (!device->keyMap.keyLayoutMap->mapKey(
scanCode, usageCode, outKeycode, outFlags)) { 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; if (status != NO_ERROR) {
*outFlags = 0; *outKeycode = 0;
return NAME_NOT_FOUND; *outFlags = 0;
*outMetaState = metaState;
}
return status;
} }
status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const { status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const {

View File

@ -197,8 +197,9 @@ public:
virtual bool hasInputProperty(int32_t deviceId, int property) const = 0; virtual bool hasInputProperty(int32_t deviceId, int property) const = 0;
virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, virtual status_t mapKey(int32_t deviceId,
int32_t* outKeycode, uint32_t* outFlags) const = 0; 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, virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
AxisInfo* outAxisInfo) const = 0; AxisInfo* outAxisInfo) const = 0;
@ -285,8 +286,9 @@ public:
virtual bool hasInputProperty(int32_t deviceId, int property) const; virtual bool hasInputProperty(int32_t deviceId, int property) const;
virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, virtual status_t mapKey(int32_t deviceId,
int32_t* outKeycode, uint32_t* outFlags) const; 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, virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
AxisInfo* outAxisInfo) const; AxisInfo* outAxisInfo) const;

View File

@ -2177,13 +2177,7 @@ void KeyboardInputMapper::process(const RawEvent* rawEvent) {
mCurrentHidUsage = 0; mCurrentHidUsage = 0;
if (isKeyboardOrGamepadKey(scanCode)) { if (isKeyboardOrGamepadKey(scanCode)) {
int32_t keyCode; processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
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);
} }
break; break;
} }
@ -2208,8 +2202,18 @@ bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
|| (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
} }
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
int32_t scanCode, uint32_t policyFlags) { 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) { if (down) {
// Rotate key codes according to orientation if needed. // 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) { if (metaStateChanged) {
mMetaState = newMetaState; mMetaState = newMetaState;
updateLedState(false); 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; 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, NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 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); getListener()->notifyKey(&args);
} }
@ -3543,8 +3553,10 @@ void TouchInputMapper::configureVirtualKeys() {
virtualKey.scanCode = virtualKeyDefinition.scanCode; virtualKey.scanCode = virtualKeyDefinition.scanCode;
int32_t keyCode; int32_t keyCode;
int32_t dummyKeyMetaState;
uint32_t flags; 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", ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
virtualKey.scanCode); virtualKey.scanCode);
mVirtualKeys.pop(); // drop the key mVirtualKeys.pop(); // drop the key

View File

@ -1154,8 +1154,7 @@ private:
bool isKeyboardOrGamepadKey(int32_t scanCode); bool isKeyboardOrGamepadKey(int32_t scanCode);
void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode);
uint32_t policyFlags);
ssize_t findKeyDown(int32_t scanCode); ssize_t findKeyDown(int32_t scanCode);

View File

@ -518,8 +518,9 @@ private:
return false; return false;
} }
virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, virtual status_t mapKey(int32_t deviceId,
int32_t* outKeycode, uint32_t* outFlags) const { int32_t scanCode, int32_t usageCode, int32_t metaState,
int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const {
Device* device = getDevice(deviceId); Device* device = getDevice(deviceId);
if (device) { if (device) {
const KeyInfo* key = getKey(device, scanCode, usageCode); const KeyInfo* key = getKey(device, scanCode, usageCode);
@ -530,6 +531,9 @@ private:
if (outFlags) { if (outFlags) {
*outFlags = key->flags; *outFlags = key->flags;
} }
if (outMetaState) {
*outMetaState = metaState;
}
return OK; return OK;
} }
} }