diff options
author | Jeff Brown <jeffbrown@google.com> | 2010-12-06 17:13:33 -0800 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2010-12-07 17:35:26 -0800 |
commit | 49ed71db425c5054e3ad9526496a7e116c89556b (patch) | |
tree | 3d3b28bdaf76d5cc531fd3b52fcbb0efb32a05ba /libs | |
parent | f30c8287525ac049d4d7589a330be5713256046b (diff) | |
download | frameworks_base-49ed71db425c5054e3ad9526496a7e116c89556b.zip frameworks_base-49ed71db425c5054e3ad9526496a7e116c89556b.tar.gz frameworks_base-49ed71db425c5054e3ad9526496a7e116c89556b.tar.bz2 |
Add support for fallback keycodes.
This change enables the framework to synthesize key events to implement
default behavior when an application does not handle a key.
For example, this change enables numeric keypad keys to perform
their associated special function when numlock is off.
The application is informed that it is processing a fallback keypress
so it can choose to ignore it.
Added a new keycode for switching applications.
Added ALT key deadkeys.
New default key mappings:
- ESC -> BACK
- Meta+ESC -> HOME
- Alt+ESC -> MENU
- Meta+Space -> SEARCH
- Meta+Tab -> APP_SWITCH
Fixed some comments.
Fixed some tests.
Change-Id: Id7f3b6645f3a350275e624547822f72652f3defe
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ui/InputDispatcher.cpp | 88 | ||||
-rw-r--r-- | libs/ui/InputReader.cpp | 33 | ||||
-rw-r--r-- | libs/ui/InputTransport.cpp | 8 | ||||
-rw-r--r-- | libs/ui/KeyCharacterMap.cpp | 79 | ||||
-rw-r--r-- | libs/ui/tests/InputDispatcher_test.cpp | 2 | ||||
-rw-r--r-- | libs/ui/tests/InputPublisherAndConsumer_test.cpp | 4 | ||||
-rw-r--r-- | libs/ui/tests/InputReader_test.cpp | 11 |
7 files changed, 163 insertions, 62 deletions
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index f1223f1..1f6a920 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -1884,7 +1884,7 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data } bool handled = false; - status_t status = connection->inputPublisher.receiveFinishedSignal(handled); + status_t status = connection->inputPublisher.receiveFinishedSignal(&handled); if (status) { LOGE("channel '%s' ~ Failed to receive finished signal. status=%d", connection->getInputChannelName(), status); @@ -3039,21 +3039,57 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( sp<Connection> connection = commandEntry->connection; bool handled = commandEntry->handled; - if (!handled && !connection->outboundQueue.isEmpty()) { + if (!connection->outboundQueue.isEmpty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next; if (dispatchEntry->inProgress && dispatchEntry->hasForegroundTarget() && dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry); - KeyEvent event; - initializeKeyEvent(&event, keyEntry); - - mLock.unlock(); - - mPolicy->dispatchUnhandledKey(connection->inputChannel, - &event, keyEntry->policyFlags); - - mLock.lock(); + if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) { + if (handled) { + // If the application handled a non-fallback key, then immediately + // cancel all fallback keys previously dispatched to the application. + // This behavior will prevent chording with fallback keys (so they cannot + // be used as modifiers) but it will ensure that fallback keys do not + // get stuck. This takes care of the case where the application does not handle + // the original DOWN so we generate a fallback DOWN but it does handle + // the original UP in which case we would not generate the fallback UP. + synthesizeCancelationEventsForConnectionLocked(connection, + InputState::CANCEL_FALLBACK_EVENTS, + "Application handled a non-fallback event."); + } else { + // If the application did not handle a non-fallback key, then ask + // the policy what to do with it. We might generate a fallback key + // event here. + KeyEvent event; + initializeKeyEvent(&event, keyEntry); + + mLock.unlock(); + + bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel, + &event, keyEntry->policyFlags, &event); + + mLock.lock(); + + if (fallback) { + // Restart the dispatch cycle using the fallback key. + keyEntry->eventTime = event.getEventTime(); + keyEntry->deviceId = event.getDeviceId(); + keyEntry->source = event.getSource(); + keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK; + keyEntry->keyCode = event.getKeyCode(); + keyEntry->scanCode = event.getScanCode(); + keyEntry->metaState = event.getMetaState(); + keyEntry->repeatCount = event.getRepeatCount(); + keyEntry->downTime = event.getDownTime(); + keyEntry->syntheticRepeat = false; + + dispatchEntry->inProgress = false; + startDispatchCycleLocked(now(), connection); + return; + } + } + } } } @@ -3371,6 +3407,7 @@ InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackKey( memento.source = entry->source; memento.keyCode = entry->keyCode; memento.scanCode = entry->scanCode; + memento.flags = entry->flags; memento.downTime = entry->downTime; return CONSISTENT; } @@ -3453,10 +3490,10 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim CancelationOptions options) { for (size_t i = 0; i < mKeyMementos.size(); ) { const KeyMemento& memento = mKeyMementos.itemAt(i); - if (shouldCancelEvent(memento.source, options)) { + if (shouldCancelKey(memento, options)) { outEvents.push(allocator->obtainKeyEntry(currentTime, memento.deviceId, memento.source, 0, - AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED, + AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode, memento.scanCode, 0, 0, memento.downTime)); mKeyMementos.removeAt(i); } else { @@ -3466,7 +3503,7 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim for (size_t i = 0; i < mMotionMementos.size(); ) { const MotionMemento& memento = mMotionMementos.itemAt(i); - if (shouldCancelEvent(memento.source, options)) { + if (shouldCancelMotion(memento, options)) { outEvents.push(allocator->obtainMotionEntry(currentTime, memento.deviceId, memento.source, 0, AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0, @@ -3502,15 +3539,30 @@ void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const { } } -bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource, +bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, CancelationOptions options) { switch (options) { - case CANCEL_POINTER_EVENTS: - return eventSource & AINPUT_SOURCE_CLASS_POINTER; + case CANCEL_ALL_EVENTS: case CANCEL_NON_POINTER_EVENTS: - return !(eventSource & AINPUT_SOURCE_CLASS_POINTER); + return true; + case CANCEL_FALLBACK_EVENTS: + return memento.flags & AKEY_EVENT_FLAG_FALLBACK; default: + return false; + } +} + +bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento, + CancelationOptions options) { + switch (options) { + case CANCEL_ALL_EVENTS: return true; + case CANCEL_POINTER_EVENTS: + return memento.source & AINPUT_SOURCE_CLASS_POINTER; + case CANCEL_NON_POINTER_EVENTS: + return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); + default: + return false; } } diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 9cc96ad..51ed09f 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -745,17 +745,6 @@ KeyboardInputMapper::~KeyboardInputMapper() { void KeyboardInputMapper::initializeLocked() { mLocked.metaState = AMETA_NONE; mLocked.downTime = 0; - - initializeLedStateLocked(mLocked.capsLockLedState, LED_CAPSL); - initializeLedStateLocked(mLocked.numLockLedState, LED_NUML); - initializeLedStateLocked(mLocked.scrollLockLedState, LED_SCROLLL); - - updateLedStateLocked(true); -} - -void KeyboardInputMapper::initializeLedStateLocked(LockedState::LedState& ledState, int32_t led) { - ledState.avail = getEventHub()->hasLed(getDeviceId(), led); - ledState.on = false; } uint32_t KeyboardInputMapper::getSources() { @@ -786,6 +775,12 @@ void KeyboardInputMapper::configure() { // Configure basic parameters. configureParameters(); + + // Reset LEDs. + { + AutoMutex _l(mLock); + resetLedStateLocked(); + } } void KeyboardInputMapper::configureParameters() { @@ -813,6 +808,7 @@ void KeyboardInputMapper::reset() { // Synthesize key up event on reset if keys are currently down. if (mLocked.keyDowns.isEmpty()) { initializeLocked(); + resetLedStateLocked(); break; // done } @@ -953,6 +949,19 @@ int32_t KeyboardInputMapper::getMetaState() { } // release lock } +void KeyboardInputMapper::resetLedStateLocked() { + initializeLedStateLocked(mLocked.capsLockLedState, LED_CAPSL); + initializeLedStateLocked(mLocked.numLockLedState, LED_NUML); + initializeLedStateLocked(mLocked.scrollLockLedState, LED_SCROLLL); + + updateLedStateLocked(true); +} + +void KeyboardInputMapper::initializeLedStateLocked(LockedState::LedState& ledState, int32_t led) { + ledState.avail = getEventHub()->hasLed(getDeviceId(), led); + ledState.on = false; +} + void KeyboardInputMapper::updateLedStateLocked(bool reset) { updateLedStateForModifierLocked(mLocked.capsLockLedState, LED_CAPSL, AMETA_CAPS_LOCK_ON, reset); @@ -966,7 +975,7 @@ void KeyboardInputMapper::updateLedStateForModifierLocked(LockedState::LedState& int32_t led, int32_t modifier, bool reset) { if (ledState.avail) { bool desiredState = (mLocked.metaState & modifier) != 0; - if (ledState.on != desiredState) { + if (reset || ledState.on != desiredState) { getEventHub()->setLedState(getDeviceId(), led, desiredState); ledState.on = desiredState; } diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index 1885691..83d9556 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -501,7 +501,7 @@ status_t InputPublisher::sendDispatchSignal() { return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH); } -status_t InputPublisher::receiveFinishedSignal(bool& outHandled) { +status_t InputPublisher::receiveFinishedSignal(bool* outHandled) { #if DEBUG_TRANSPORT_ACTIONS LOGD("channel '%s' publisher ~ receiveFinishedSignal", mChannel->getName().string()); @@ -510,13 +510,13 @@ status_t InputPublisher::receiveFinishedSignal(bool& outHandled) { char signal; status_t result = mChannel->receiveSignal(& signal); if (result) { - outHandled = false; + *outHandled = false; return result; } if (signal == INPUT_SIGNAL_FINISHED_HANDLED) { - outHandled = true; + *outHandled = true; } else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) { - outHandled = false; + *outHandled = false; } else { LOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer", mChannel->getName().string(), signal); diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp index e689c4b..9bfa8f6 100644 --- a/libs/ui/KeyCharacterMap.cpp +++ b/libs/ui/KeyCharacterMap.cpp @@ -141,9 +141,8 @@ int32_t KeyCharacterMap::getKeyboardType() const { char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const { char16_t result = 0; - ssize_t index = mKeys.indexOfKey(keyCode); - if (index >= 0) { - const Key* key = mKeys.valueAt(index); + const Key* key; + if (getKey(keyCode, &key)) { result = key->label; } #if DEBUG_MAPPING @@ -154,9 +153,8 @@ char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const { char16_t KeyCharacterMap::getNumber(int32_t keyCode) const { char16_t result = 0; - ssize_t index = mKeys.indexOfKey(keyCode); - if (index >= 0) { - const Key* key = mKeys.valueAt(index); + const Key* key; + if (getKey(keyCode, &key)) { result = key->number; } #if DEBUG_MAPPING @@ -167,15 +165,10 @@ char16_t KeyCharacterMap::getNumber(int32_t keyCode) const { char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const { char16_t result = 0; - ssize_t index = mKeys.indexOfKey(keyCode); - if (index >= 0) { - const Key* key = mKeys.valueAt(index); - for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { - if ((behavior->metaState & metaState) == behavior->metaState) { - result = behavior->character; - break; - } - } + const Key* key; + const Behavior* behavior; + if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { + result = behavior->character; } #if DEBUG_MAPPING LOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result); @@ -183,13 +176,33 @@ char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const return result; } +bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState, + FallbackAction* outFallbackAction) const { + outFallbackAction->keyCode = 0; + outFallbackAction->metaState = 0; + + bool result = false; + const Key* key; + const Behavior* behavior; + if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { + outFallbackAction->keyCode = behavior->fallbackKeyCode; + outFallbackAction->metaState = metaState & ~behavior->metaState; + result = true; + } +#if DEBUG_MAPPING + LOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, " + "fallback keyCode=%d, fallback metaState=0x%08x.", + keyCode, metaState, result ? "true" : "false", + outFallbackAction->keyCode, outFallbackAction->metaState); +#endif + return result; +} + char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars, int32_t metaState) const { char16_t result = 0; - ssize_t index = mKeys.indexOfKey(keyCode); - if (index >= 0) { - const Key* key = mKeys.valueAt(index); - + const Key* key; + if (getKey(keyCode, &key)) { // Try to find the most general behavior that maps to this character. // For example, the base key behavior will usually be last in the list. // However, if we find a perfect meta state match for one behavior then use that one. @@ -238,7 +251,7 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t } #if DEBUG_MAPPING LOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", - deviceId, toString(chars, numChars).string(), outEvents.size()); + deviceId, toString(chars, numChars).string(), int32_t(outEvents.size())); for (size_t i = 0; i < outEvents.size(); i++) { LOGD(" Key: keyCode=%d, metaState=0x%08x, %s.", outEvents[i].getKeyCode(), outEvents[i].getMetaState(), @@ -248,6 +261,32 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t return true; } +bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const { + ssize_t index = mKeys.indexOfKey(keyCode); + if (index >= 0) { + *outKey = mKeys.valueAt(index); + return true; + } + return false; +} + +bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState, + const Key** outKey, const Behavior** outBehavior) const { + const Key* key; + if (getKey(keyCode, &key)) { + const Behavior* behavior = key->firstBehavior; + while (behavior) { + if ((behavior->metaState & metaState) == behavior->metaState) { + *outKey = key; + *outBehavior = behavior; + return true; + } + behavior = behavior->next; + } + } + return false; +} + bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const { if (!ch) { return false; diff --git a/libs/ui/tests/InputDispatcher_test.cpp b/libs/ui/tests/InputDispatcher_test.cpp index 68f9037..7e17c57 100644 --- a/libs/ui/tests/InputDispatcher_test.cpp +++ b/libs/ui/tests/InputDispatcher_test.cpp @@ -66,7 +66,7 @@ private: } virtual bool dispatchUnhandledKey(const sp<InputChannel>& inputChannel, - const KeyEvent* keyEvent, uint32_t policyFlags) { + const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) { return false; } diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp index c6eac25..903fcaf 100644 --- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp @@ -123,7 +123,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { << "consumer sendFinishedSignal should return OK"; bool handled = false; - status = mPublisher->receiveFinishedSignal(handled); + status = mPublisher->receiveFinishedSignal(&handled); ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK"; ASSERT_TRUE(handled) @@ -287,7 +287,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent( << "consumer sendFinishedSignal should return OK"; bool handled = true; - status = mPublisher->receiveFinishedSignal(handled); + status = mPublisher->receiveFinishedSignal(&handled); ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK"; ASSERT_FALSE(handled) diff --git a/libs/ui/tests/InputReader_test.cpp b/libs/ui/tests/InputReader_test.cpp index d6c2cbd..97cbc25 100644 --- a/libs/ui/tests/InputReader_test.cpp +++ b/libs/ui/tests/InputReader_test.cpp @@ -1137,6 +1137,7 @@ protected: mFakeDispatcher = new FakeInputDispatcher(); mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeDispatcher); + mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME)); } @@ -1753,7 +1754,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 1, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 1, 0); + EV_KEY, KEY_CAPSLOCK, AKEYCODE_CAPS_LOCK, 0, 0); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); @@ -2225,19 +2226,19 @@ void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) { } -TEST_F(SingleTouchInputMapperTest, GetSources_WhenDisplayTypeIsTouchPad_ReturnsTouchPad) { +TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareAxes(POSITION); - addConfigurationProperty("touch.displayType", "touchPad"); + addConfigurationProperty("touch.deviceType", "touchPad"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); } -TEST_F(SingleTouchInputMapperTest, GetSources_WhenDisplayTypeIsTouchScreen_ReturnsTouchScreen) { +TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareAxes(POSITION); - addConfigurationProperty("touch.displayType", "touchScreen"); + addConfigurationProperty("touch.deviceType", "touchScreen"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources()); |