summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2010-12-06 17:13:33 -0800
committerJeff Brown <jeffbrown@google.com>2010-12-07 17:35:26 -0800
commit02d85b5021dc3e9c042e1e3426fae2f0a903595b (patch)
treecfd014e8539fbed0c51d586fec095d1969f0eed1 /libs
parentb5a00fcb71426492f248ed49a0514a9b8d385065 (diff)
downloadframeworks_native-02d85b5021dc3e9c042e1e3426fae2f0a903595b.zip
frameworks_native-02d85b5021dc3e9c042e1e3426fae2f0a903595b.tar.gz
frameworks_native-02d85b5021dc3e9c042e1e3426fae2f0a903595b.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.cpp88
-rw-r--r--libs/ui/InputReader.cpp33
-rw-r--r--libs/ui/InputTransport.cpp8
-rw-r--r--libs/ui/KeyCharacterMap.cpp79
-rw-r--r--libs/ui/tests/InputDispatcher_test.cpp2
-rw-r--r--libs/ui/tests/InputPublisherAndConsumer_test.cpp4
-rw-r--r--libs/ui/tests/InputReader_test.cpp11
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());