summaryrefslogtreecommitdiffstats
path: root/libs/ui
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ui')
-rw-r--r--libs/ui/EventHub.cpp210
-rw-r--r--libs/ui/GraphicBuffer.cpp20
-rw-r--r--libs/ui/InputDispatcher.cpp99
-rw-r--r--libs/ui/InputReader.cpp113
-rw-r--r--libs/ui/KeyCharacterMap.cpp42
5 files changed, 402 insertions, 82 deletions
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 944731d..97a7528 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -94,7 +94,7 @@ static inline const char* toString(bool value) {
EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
: id(_id), path(_path), name(name), classes(0)
- , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), fd(-1), next(NULL) {
+ , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), defaultKeyMap(false), fd(-1), next(NULL) {
}
EventHub::device_t::~device_t() {
@@ -103,7 +103,7 @@ EventHub::device_t::~device_t() {
}
EventHub::EventHub(void)
- : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0)
+ : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(-1)
, mDevicesById(0), mNumDevicesById(0)
, mOpeningDevices(0), mClosingDevices(0)
, mDevices(0), mFDs(0), mFDCount(0), mOpened(false), mNeedToSendFinishedDeviceScan(false)
@@ -325,6 +325,39 @@ void EventHub::addExcludedDevice(const char* deviceName)
mExcludedDevices.push_back(name);
}
+bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
+ AutoMutex _l(mLock);
+ device_t* device = getDeviceLocked(deviceId);
+ if (device) {
+ uint8_t bitmask[sizeof_bit_array(LED_MAX + 1)];
+ memset(bitmask, 0, sizeof(bitmask));
+ if (ioctl(device->fd, EVIOCGBIT(EV_LED, sizeof(bitmask)), bitmask) >= 0) {
+ if (test_bit(led, bitmask)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
+ AutoMutex _l(mLock);
+ device_t* device = getDeviceLocked(deviceId);
+ if (device) {
+ struct input_event ev;
+ ev.time.tv_sec = 0;
+ ev.time.tv_usec = 0;
+ ev.type = EV_LED;
+ ev.code = led;
+ ev.value = on ? 1 : 0;
+
+ ssize_t nWrite;
+ do {
+ nWrite = write(device->fd, &ev, sizeof(struct input_event));
+ } while (nWrite == -1 && errno == EINTR);
+ }
+}
+
EventHub::device_t* EventHub::getDeviceLocked(int32_t deviceId) const
{
if (deviceId == 0) deviceId = mFirstKeyboardId;
@@ -760,54 +793,42 @@ int EventHub::openDevice(const char *deviceName) {
#endif
if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
- char tmpfn[sizeof(name)];
- char keylayoutFilename[300];
-
// a more descriptive name
device->name = name;
- // replace all the spaces with underscores
- strcpy(tmpfn, name);
- for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
- *p = '_';
-
- // find the .kl file we need for this device
- const char* root = getenv("ANDROID_ROOT");
- snprintf(keylayoutFilename, sizeof(keylayoutFilename),
- "%s/usr/keylayout/%s.kl", root, tmpfn);
- bool defaultKeymap = false;
- if (access(keylayoutFilename, R_OK)) {
- snprintf(keylayoutFilename, sizeof(keylayoutFilename),
- "%s/usr/keylayout/%s", root, "qwerty.kl");
- defaultKeymap = true;
- }
- status_t status = device->layoutMap->load(keylayoutFilename);
- if (status) {
- LOGE("Error %d loading key layout.", status);
- }
+ // Configure the keymap for the device.
+ configureKeyMap(device);
- // tell the world about the devname (the descriptive name)
- if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
+ // Tell the world about the devname (the descriptive name)
+ if (!mHaveFirstKeyboard && !device->defaultKeyMap && strstr(name, "-keypad")) {
// the built-in keyboard has a well-known device ID of 0,
// this device better not go away.
mHaveFirstKeyboard = true;
mFirstKeyboardId = device->id;
- property_set("hw.keyboards.0.devname", name);
+ setKeyboardProperties(device, true);
} else {
// ensure mFirstKeyboardId is set to -something-.
- if (mFirstKeyboardId == 0) {
+ if (mFirstKeyboardId == -1) {
mFirstKeyboardId = device->id;
+ setKeyboardProperties(device, true);
+ }
+ }
+ setKeyboardProperties(device, false);
+
+ // Load the keylayout.
+ if (!device->keyLayoutFilename.isEmpty()) {
+ status_t status = device->layoutMap->load(device->keyLayoutFilename);
+ if (status) {
+ LOGE("Error %d loading key layout file '%s'.", status,
+ device->keyLayoutFilename.string());
}
}
- char propName[100];
- sprintf(propName, "hw.keyboards.%u.devname", device->id);
- property_set(propName, name);
// 'Q' key support = cheap test of whether this is an alpha-capable kbd
if (hasKeycodeLocked(device, AKEYCODE_Q)) {
device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
}
-
+
// See if this device has a DPAD.
if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
@@ -816,7 +837,7 @@ int EventHub::openDevice(const char *deviceName) {
hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
device->classes |= INPUT_DEVICE_CLASS_DPAD;
}
-
+
// See if this device has a gamepad.
for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES); i++) {
if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
@@ -825,8 +846,9 @@ int EventHub::openDevice(const char *deviceName) {
}
}
- LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
- device->id, name, propName, keylayoutFilename);
+ LOGI("New keyboard: device->id=0x%x devname='%s' keylayout='%s' keycharactermap='%s'\n",
+ device->id, name,
+ device->keyLayoutFilename.string(), device->keyCharacterMapFilename.string());
}
// If the device isn't recognized as something we handle, don't monitor it.
@@ -852,6 +874,109 @@ int EventHub::openDevice(const char *deviceName) {
return 0;
}
+void EventHub::configureKeyMap(device_t* device) {
+ // As an initial key map name, try using the device name.
+ String8 keyMapName(device->name);
+ char* p = keyMapName.lockBuffer(keyMapName.size());
+ while (*p) {
+ if (*p == ' ') *p = '_';
+ p++;
+ }
+ keyMapName.unlockBuffer();
+
+ if (probeKeyMap(device, keyMapName, false)) return;
+
+ // TODO Consider allowing the user to configure a specific key map somehow.
+
+ // Try the Generic key map.
+ // TODO Apply some additional heuristics here to figure out what kind of
+ // generic key map to use (US English, etc.).
+ keyMapName.setTo("Generic");
+ if (probeKeyMap(device, keyMapName, true)) return;
+
+ // Fall back on the old style catchall qwerty key map.
+ keyMapName.setTo("qwerty");
+ if (probeKeyMap(device, keyMapName, true)) return;
+
+ // Give up!
+ keyMapName.setTo("unknown");
+ selectKeyMap(device, keyMapName, true);
+ LOGE("Could not determine key map for device '%s'.", device->name.string());
+}
+
+bool EventHub::probeKeyMap(device_t* device, const String8& keyMapName, bool defaultKeyMap) {
+ const char* root = getenv("ANDROID_ROOT");
+
+ // TODO Consider also looking somewhere in a writeable partition like /data for a
+ // custom keymap supplied by the user for this device.
+ bool haveKeyLayout = !device->keyLayoutFilename.isEmpty();
+ if (!haveKeyLayout) {
+ device->keyLayoutFilename.setTo(root);
+ device->keyLayoutFilename.append("/usr/keylayout/");
+ device->keyLayoutFilename.append(keyMapName);
+ device->keyLayoutFilename.append(".kl");
+ if (access(device->keyLayoutFilename.string(), R_OK)) {
+ device->keyLayoutFilename.clear();
+ } else {
+ haveKeyLayout = true;
+ }
+ }
+
+ bool haveKeyCharacterMap = !device->keyCharacterMapFilename.isEmpty();
+ if (!haveKeyCharacterMap) {
+ device->keyCharacterMapFilename.setTo(root);
+ device->keyCharacterMapFilename.append("/usr/keychars/");
+ device->keyCharacterMapFilename.append(keyMapName);
+ device->keyCharacterMapFilename.append(".kcm.bin");
+ if (access(device->keyCharacterMapFilename.string(), R_OK)) {
+ device->keyCharacterMapFilename.clear();
+ } else {
+ haveKeyCharacterMap = true;
+ }
+ }
+
+ if (haveKeyLayout || haveKeyCharacterMap) {
+ selectKeyMap(device, keyMapName, defaultKeyMap);
+ }
+ return haveKeyLayout && haveKeyCharacterMap;
+}
+
+void EventHub::selectKeyMap(device_t* device,
+ const String8& keyMapName, bool defaultKeyMap) {
+ if (device->keyMapName.isEmpty()) {
+ device->keyMapName.setTo(keyMapName);
+ device->defaultKeyMap = defaultKeyMap;
+ }
+}
+
+void EventHub::setKeyboardProperties(device_t* device, bool firstKeyboard) {
+ int32_t id = firstKeyboard ? 0 : device->id;
+
+ char propName[100];
+ sprintf(propName, "hw.keyboards.%u.devname", id);
+ property_set(propName, device->name.string());
+ sprintf(propName, "hw.keyboards.%u.keymap", id);
+ property_set(propName, device->keyMapName.string());
+ sprintf(propName, "hw.keyboards.%u.klfile", id);
+ property_set(propName, device->keyLayoutFilename.string());
+ sprintf(propName, "hw.keyboards.%u.kcmfile", id);
+ property_set(propName, device->keyCharacterMapFilename.string());
+}
+
+void EventHub::clearKeyboardProperties(device_t* device, bool firstKeyboard) {
+ int32_t id = firstKeyboard ? 0 : device->id;
+
+ char propName[100];
+ sprintf(propName, "hw.keyboards.%u.devname", id);
+ property_set(propName, "");
+ sprintf(propName, "hw.keyboards.%u.keymap", id);
+ property_set(propName, "");
+ sprintf(propName, "hw.keyboards.%u.klfile", id);
+ property_set(propName, "");
+ sprintf(propName, "hw.keyboards.%u.kcmfile", id);
+ property_set(propName, "");
+}
+
bool EventHub::hasKeycodeLocked(device_t* device, int keycode) const
{
if (device->keyBitmask == NULL || device->layoutMap == NULL) {
@@ -909,13 +1034,10 @@ int EventHub::closeDevice(const char *deviceName) {
if (device->id == mFirstKeyboardId) {
LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
device->path.string(), mFirstKeyboardId);
- mFirstKeyboardId = 0;
- property_set("hw.keyboards.0.devname", NULL);
+ mFirstKeyboardId = -1;
+ clearKeyboardProperties(device, true);
}
- // clear the property
- char propName[100];
- sprintf(propName, "hw.keyboards.%u.devname", device->id);
- property_set(propName, NULL);
+ clearKeyboardProperties(device, false);
return 0;
}
}
@@ -1014,7 +1136,11 @@ void EventHub::dump(String8& dump) {
}
dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
- dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n", device->keylayoutFilename.string());
+ dump.appendFormat(INDENT3 "KeyMapName: %s\n", device->keyMapName.string());
+ dump.appendFormat(INDENT3 "KeyLayoutFilename: %s\n",
+ device->keyLayoutFilename.string());
+ dump.appendFormat(INDENT3 "KeyCharacterMapFilename: %s\n",
+ device->keyCharacterMapFilename.string());
}
}
} // release lock
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 519c277..436e064 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -77,6 +77,19 @@ GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
handle = inHandle;
}
+GraphicBuffer::GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership)
+ : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
+ mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mIndex(-1), mWrappedBuffer(buffer)
+{
+ width = buffer->width;
+ height = buffer->height;
+ stride = buffer->stride;
+ format = buffer->format;
+ usage = buffer->usage;
+ handle = buffer->handle;
+}
+
GraphicBuffer::~GraphicBuffer()
{
if (handle) {
@@ -87,12 +100,14 @@ GraphicBuffer::~GraphicBuffer()
void GraphicBuffer::free_handle()
{
if (mOwner == ownHandle) {
+ mBufferMapper.unregisterBuffer(handle);
native_handle_close(handle);
native_handle_delete(const_cast<native_handle*>(handle));
} else if (mOwner == ownData) {
GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
allocator.free(handle);
}
+ mWrappedBuffer = 0;
}
status_t GraphicBuffer::initCheck() const {
@@ -253,6 +268,11 @@ status_t GraphicBuffer::unflatten(void const* buffer, size_t size,
}
mOwner = ownHandle;
+
+ if (handle != 0) {
+ mBufferMapper.registerBuffer(handle);
+ }
+
return NO_ERROR;
}
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 6ba19d7..949dc4d 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -149,7 +149,8 @@ bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
bool InputWindow::isTrustedOverlay() const {
return layoutParamsType == TYPE_INPUT_METHOD
- || layoutParamsType == TYPE_INPUT_METHOD_DIALOG;
+ || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
+ || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
}
@@ -1350,7 +1351,7 @@ void InputDispatcher::addMonitoringTargetsLocked() {
target.flags = 0;
target.xOffset = 0;
target.yOffset = 0;
- target.windowType = InputWindow::TYPE_SYSTEM_OVERLAY;
+ target.windowType = -1;
}
}
@@ -2612,6 +2613,82 @@ void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
}
}
+bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
+ const sp<InputChannel>& toChannel) {
+#if DEBUG_FOCUS
+ LOGD("transferTouchFocus: fromChannel=%s, toChannel=%s",
+ fromChannel->getName().string(), toChannel->getName().string());
+#endif
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ const InputWindow* fromWindow = getWindowLocked(fromChannel);
+ const InputWindow* toWindow = getWindowLocked(toChannel);
+ if (! fromWindow || ! toWindow) {
+#if DEBUG_FOCUS
+ LOGD("Cannot transfer focus because from or to window not found.");
+#endif
+ return false;
+ }
+ if (fromWindow == toWindow) {
+#if DEBUG_FOCUS
+ LOGD("Trivial transfer to same window.");
+#endif
+ return true;
+ }
+
+ bool found = false;
+ for (size_t i = 0; i < mTouchState.windows.size(); i++) {
+ const TouchedWindow& touchedWindow = mTouchState.windows[i];
+ if (touchedWindow.window == fromWindow) {
+ int32_t oldTargetFlags = touchedWindow.targetFlags;
+ BitSet32 pointerIds = touchedWindow.pointerIds;
+
+ mTouchState.windows.removeAt(i);
+
+ int32_t newTargetFlags = 0;
+ if (oldTargetFlags & InputTarget::FLAG_FOREGROUND) {
+ newTargetFlags |= InputTarget::FLAG_FOREGROUND;
+ if (toWindow->layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH) {
+ newTargetFlags |= InputTarget::FLAG_SPLIT;
+ }
+ }
+ mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds);
+
+ found = true;
+ break;
+ }
+ }
+
+ if (! found) {
+#if DEBUG_FOCUS
+ LOGD("Focus transfer failed because from window did not have focus.");
+#endif
+ return false;
+ }
+
+ ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
+ ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
+ if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
+ sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex);
+ sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);
+
+ fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
+ synthesizeCancelationEventsForConnectionLocked(fromConnection,
+ InputState::CANCEL_POINTER_EVENTS,
+ "transferring touch focus from this window to another window");
+ }
+
+#if DEBUG_FOCUS
+ logDispatchStateLocked();
+#endif
+ } // release lock
+
+ // Wake up poll loop since it may need to make new input dispatching choices.
+ mLooper->wake();
+ return true;
+}
+
void InputDispatcher::logDispatchStateLocked() {
String8 dump;
dumpDispatchStateLocked(dump);
@@ -3338,6 +3415,24 @@ void InputDispatcher::InputState::clear() {
mMotionMementos.clear();
}
+void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
+ for (size_t i = 0; i < mMotionMementos.size(); i++) {
+ const MotionMemento& memento = mMotionMementos.itemAt(i);
+ if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
+ for (size_t j = 0; j < other.mMotionMementos.size(); ) {
+ const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j);
+ if (memento.deviceId == otherMemento.deviceId
+ && memento.source == otherMemento.source) {
+ other.mMotionMementos.removeAt(j);
+ } else {
+ j += 1;
+ }
+ }
+ other.mMotionMementos.push(memento);
+ }
+ }
+}
+
bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource,
CancelationOptions options) {
switch (options) {
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index ce0d880..01ebda9 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -70,41 +70,73 @@ static inline const char* toString(bool value) {
return value ? "true" : "false";
}
+int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
+ int32_t newMetaState;
+ if (down) {
+ newMetaState = oldMetaState | mask;
+ } else {
+ newMetaState = oldMetaState &
+ ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
+ }
+
+ if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
+ newMetaState |= AMETA_ALT_ON;
+ }
+
+ if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
+ newMetaState |= AMETA_SHIFT_ON;
+ }
+
+ if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
+ newMetaState |= AMETA_CTRL_ON;
+ }
+
+ if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
+ newMetaState |= AMETA_META_ON;
+ }
+ return newMetaState;
+}
+
+int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) {
+ if (down) {
+ return oldMetaState;
+ } else {
+ return oldMetaState ^ mask;
+ }
+}
int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
int32_t mask;
switch (keyCode) {
case AKEYCODE_ALT_LEFT:
- mask = AMETA_ALT_LEFT_ON;
- break;
+ return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState);
case AKEYCODE_ALT_RIGHT:
- mask = AMETA_ALT_RIGHT_ON;
- break;
+ return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState);
case AKEYCODE_SHIFT_LEFT:
- mask = AMETA_SHIFT_LEFT_ON;
- break;
+ return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState);
case AKEYCODE_SHIFT_RIGHT:
- mask = AMETA_SHIFT_RIGHT_ON;
- break;
+ return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState);
case AKEYCODE_SYM:
- mask = AMETA_SYM_ON;
- break;
+ return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState);
+ case AKEYCODE_FUNCTION:
+ return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState);
+ case AKEYCODE_CTRL_LEFT:
+ return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState);
+ case AKEYCODE_CTRL_RIGHT:
+ return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState);
+ case AKEYCODE_META_LEFT:
+ return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState);
+ case AKEYCODE_META_RIGHT:
+ return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState);
+ case AKEYCODE_CAPS_LOCK:
+ return toggleLockedMetaState(AMETA_CAPS_LOCK_LATCHED, down, oldMetaState);
+ case AKEYCODE_NUM_LOCK:
+ return toggleLockedMetaState(AMETA_NUM_LOCK_LATCHED, down, oldMetaState);
+ case AKEYCODE_SCROLL_LOCK:
+ return toggleLockedMetaState(AMETA_SCROLL_LOCK_LATCHED, down, oldMetaState);
default:
return oldMetaState;
}
-
- int32_t newMetaState = down ? oldMetaState | mask : oldMetaState & ~ mask
- & ~ (AMETA_ALT_ON | AMETA_SHIFT_ON);
-
- if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
- newMetaState |= AMETA_ALT_ON;
- }
-
- if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
- newMetaState |= AMETA_SHIFT_ON;
- }
-
- return newMetaState;
}
static const int32_t keyCodeRotationMap[][4] = {
@@ -842,6 +874,17 @@ 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() {
@@ -966,6 +1009,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
if (oldMetaState != newMetaState) {
mLocked.metaState = newMetaState;
metaStateChanged = true;
+ updateLedStateLocked(false);
}
downTime = mLocked.downTime;
@@ -975,6 +1019,9 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
getContext()->updateGlobalMetaState();
}
+ if (policyFlags & POLICY_FLAG_FUNCTION) {
+ newMetaState |= AMETA_FUNCTION_ON;
+ }
getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
@@ -1010,6 +1057,26 @@ int32_t KeyboardInputMapper::getMetaState() {
} // release lock
}
+void KeyboardInputMapper::updateLedStateLocked(bool reset) {
+ updateLedStateForModifierLocked(mLocked.capsLockLedState, LED_CAPSL,
+ AMETA_CAPS_LOCK_LATCHED, reset);
+ updateLedStateForModifierLocked(mLocked.numLockLedState, LED_NUML,
+ AMETA_NUM_LOCK_LATCHED, reset);
+ updateLedStateForModifierLocked(mLocked.scrollLockLedState, LED_SCROLLL,
+ AMETA_SCROLL_LOCK_LATCHED, reset);
+}
+
+void KeyboardInputMapper::updateLedStateForModifierLocked(LockedState::LedState& ledState,
+ int32_t led, int32_t modifier, bool reset) {
+ if (ledState.avail) {
+ bool desiredState = (mLocked.metaState & modifier) != 0;
+ if (ledState.on != desiredState) {
+ getEventHub()->setLedState(getDeviceId(), led, desiredState);
+ ledState.on = desiredState;
+ }
+ }
+}
+
// --- TrackballInputMapper ---
diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp
index e891181..870a45c 100644
--- a/libs/ui/KeyCharacterMap.cpp
+++ b/libs/ui/KeyCharacterMap.cpp
@@ -156,26 +156,38 @@ KeyCharacterMap::find_key(int keycode)
KeyCharacterMap*
KeyCharacterMap::load(int id)
{
- KeyCharacterMap* rv = NULL;
+ KeyCharacterMap* map;
char path[PATH_MAX];
char propName[100];
char dev[PROPERTY_VALUE_MAX];
- char tmpfn[PROPERTY_VALUE_MAX];
+ char fn[PROPERTY_VALUE_MAX];
int err;
+
+ // Check whether the EventHub has set a key character map filename for us already.
+ sprintf(propName, "hw.keyboards.%u.kcmfile", id);
+ err = property_get(propName, fn, "");
+ if (err > 0) {
+ map = try_file(fn);
+ if (map) {
+ return map;
+ }
+ LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, fn);
+ }
+
+ // Try using the device name.
const char* root = getenv("ANDROID_ROOT");
sprintf(propName, "hw.keyboards.%u.devname", id);
err = property_get(propName, dev, "");
if (err > 0) {
// replace all the spaces with underscores
- strcpy(tmpfn, dev);
- for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
+ strcpy(fn, dev);
+ for (char *p = strchr(fn, ' '); p && *p; p = strchr(p + 1, ' '))
*p = '_';
- snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, tmpfn);
- //LOGD("load: dev='%s' path='%s'\n", dev, path);
- rv = try_file(path);
- if (rv != NULL) {
- return rv;
+ snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, fn);
+ map = try_file(path);
+ if (map) {
+ return map;
}
LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, dev);
} else {
@@ -183,14 +195,14 @@ KeyCharacterMap::load(int id)
}
snprintf(path, sizeof(path), "%s/usr/keychars/qwerty.kcm.bin", root);
- rv = try_file(path);
- if (rv == NULL) {
- LOGE("Can't find any keycharmaps (also tried %s)", path);
- return NULL;
+ map = try_file(path);
+ if (map) {
+ LOGW("Using default keymap: %s", path);
+ return map;
}
- LOGW("Using default keymap: %s", path);
- return rv;
+ LOGE("Can't find any keycharmaps (also tried %s)", path);
+ return NULL;
}
KeyCharacterMap*