Add keycodes and meta-key modifiers to support external keyboards.

Added new key maps for external keyboards.  These maps are intended to
be shared across devices by inheriting the "keyboards.mk" product
makefile as part of the device's product definition.

One of the trickier changes here was to unwind some code in
MetaKeyKeyListener that assumed that only the low 8 bits of the meta key
state were actually used.  The new code abandons bitshifts in favor
of simple conditionals that are probably easier to read anyways.
The special meta key state constants used by MetaKeyKeyListener
are now (@hide) defined in KeyEvent now so as to make it clearer that they
share the same code space even if those codes are not valid for KeyEvents.

The EventHub now takes care of detecting the appropriate key layout
map and key character map when the device is added and sets system
properties accordingly.  This avoids having duplicate code in
KeyCharacterMap to probe for the appropriate key character map
although the current probing mechanism has been preserved for legacy
reasons just in case.

Added support for tracking caps lock, num lock and scroll lock and
turning their corresponding LEDs on and off as needed.

The key character map format will need to be updated to correctly support
PC style external keyboard semantics related to modifier keys.
That will come in a later change so caps lock doesn't actually do
anything right now except turn the shiny LEDs on and off...

Added a list of symbolic key names to KeyEvent and improved the toString()
output for debug diagnosis.  Having this list in a central place in the
framework also allows us to remove it from Monkey so there is one less
thing to maintain when we add new keycodes.

Bug: 2912307
Change-Id: If8c25e8d50a7c29bbf5d663c94284f5f86de5da4
This commit is contained in:
Jeff Brown 2010-09-12 17:55:08 -07:00
parent cc13ed145c
commit 6a817e22e4
9 changed files with 388 additions and 87 deletions

View File

@ -187,6 +187,9 @@ public:
virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
uint8_t* outFlags) const = 0;
virtual bool hasLed(int32_t deviceId, int32_t led) const = 0;
virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0;
virtual void dump(String8& dump) = 0;
};
@ -198,9 +201,9 @@ public:
status_t errorCheck() const;
virtual uint32_t getDeviceClasses(int32_t deviceId) const;
virtual String8 getDeviceName(int32_t deviceId) const;
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const;
@ -218,6 +221,9 @@ public:
virtual bool getEvent(RawEvent* outEvent);
virtual bool hasLed(int32_t deviceId, int32_t led) const;
virtual void setLedState(int32_t deviceId, int32_t led, bool on);
virtual void dump(String8& dump);
protected:
@ -240,7 +246,10 @@ private:
uint32_t classes;
uint8_t* keyBitmask;
KeyLayoutMap* layoutMap;
String8 keylayoutFilename;
String8 keyMapName;
bool defaultKeyMap;
String8 keyLayoutFilename;
String8 keyCharacterMapFilename;
int fd;
device_t* next;
@ -250,13 +259,19 @@ private:
device_t* getDeviceLocked(int32_t deviceId) const;
bool hasKeycodeLocked(device_t* device, int keycode) const;
int32_t getScanCodeStateLocked(device_t* device, int32_t scanCode) const;
int32_t getKeyCodeStateLocked(device_t* device, int32_t keyCode) const;
int32_t getSwitchStateLocked(device_t* device, int32_t sw) const;
bool markSupportedKeyCodesLocked(device_t* device, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) const;
void configureKeyMap(device_t* device);
bool probeKeyMap(device_t* device, const String8& keyMapName, bool defaultKeyMap);
void selectKeyMap(device_t* device, const String8& keyMapName, bool defaultKeyMap);
void setKeyboardProperties(device_t* device, bool firstKeyboard);
void clearKeyboardProperties(device_t* device, bool firstKeyboard);
// Protect all internal state.
mutable Mutex mLock;

View File

@ -76,7 +76,7 @@ namespace android {
*/
enum {
/* These flags originate in RawEvents and are generally set in the key map.
* See also labels for policy flags in KeycodeLabels.h. */
* NOTE: If you edit these flags, also edit labels in KeycodeLabels.h. */
POLICY_FLAG_WAKE = 0x00000001,
POLICY_FLAG_WAKE_DROPPED = 0x00000002,
@ -87,6 +87,7 @@ enum {
POLICY_FLAG_MENU = 0x00000040,
POLICY_FLAG_LAUNCHER = 0x00000080,
POLICY_FLAG_VIRTUAL = 0x00000100,
POLICY_FLAG_FUNCTION = 0x00000200,
POLICY_FLAG_RAW_MASK = 0x0000ffff,

View File

@ -419,9 +419,18 @@ private:
Vector<KeyDown> keyDowns; // keys that are down
int32_t metaState;
nsecs_t downTime; // time of most recent key down
struct LedState {
bool avail; // led is available
bool on; // we think the led is currently on
};
LedState capsLockLedState;
LedState numLockLedState;
LedState scrollLockLedState;
} mLocked;
void initializeLocked();
void initializeLedStateLocked(LockedState::LedState& ledState, int32_t led);
bool isKeyboardOrGamepadKey(int32_t scanCode);
@ -429,6 +438,10 @@ private:
uint32_t policyFlags);
ssize_t findKeyDownLocked(int32_t scanCode);
void updateLedStateLocked(bool reset);
void updateLedStateForModifierLocked(LockedState::LedState& ledState, int32_t led,
int32_t modifier, bool reset);
};

View File

@ -135,6 +135,59 @@ static const KeycodeLabel KEYCODES[] = {
{ "BUTTON_START", 108 },
{ "BUTTON_SELECT", 109 },
{ "BUTTON_MODE", 110 },
{ "ESCAPE", 111 },
{ "FORWARD_DEL", 112 },
{ "CTRL_LEFT", 113 },
{ "CTRL_RIGHT", 114 },
{ "CAPS_LOCK", 115 },
{ "SCROLL_LOCK", 116 },
{ "META_LEFT", 117 },
{ "META_RIGHT", 118 },
{ "FUNCTION", 119 },
{ "SYSRQ", 120 },
{ "BREAK", 121 },
{ "MOVE_HOME", 122 },
{ "MOVE_END", 123 },
{ "INSERT", 124 },
{ "FORWARD", 125 },
{ "MEDIA_PLAY", 126 },
{ "MEDIA_PAUSE", 127 },
{ "MEDIA_CLOSE", 128 },
{ "MEDIA_EJECT", 129 },
{ "MEDIA_RECORD", 130 },
{ "F1", 131 },
{ "F2", 132 },
{ "F3", 133 },
{ "F4", 134 },
{ "F5", 135 },
{ "F6", 136 },
{ "F7", 137 },
{ "F8", 138 },
{ "F9", 139 },
{ "F10", 140 },
{ "F11", 141 },
{ "F12", 142 },
{ "NUM_LOCK", 143 },
{ "NUMPAD_0", 144 },
{ "NUMPAD_1", 145 },
{ "NUMPAD_2", 146 },
{ "NUMPAD_3", 147 },
{ "NUMPAD_4", 148 },
{ "NUMPAD_5", 149 },
{ "NUMPAD_6", 150 },
{ "NUMPAD_7", 151 },
{ "NUMPAD_8", 152 },
{ "NUMPAD_9", 153 },
{ "NUMPAD_DIVIDE", 154 },
{ "NUMPAD_MULTIPLY", 155 },
{ "NUMPAD_SUBTRACT", 156 },
{ "NUMPAD_ADD", 157 },
{ "NUMPAD_DOT", 158 },
{ "NUMPAD_COMMA", 159 },
{ "NUMPAD_ENTER", 160 },
{ "NUMPAD_EQUALS", 161 },
{ "NUMPAD_LEFT_PAREN", 162 },
{ "NUMPAD_RIGHT_PAREN", 163 },
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
@ -142,7 +195,7 @@ static const KeycodeLabel KEYCODES[] = {
{ NULL, 0 }
};
// See also policy flags in Input.h.
// NOTE: If you edit these flags, also edit policy flags in Input.h.
static const KeycodeLabel FLAGS[] = {
{ "WAKE", 0x00000001 },
{ "WAKE_DROPPED", 0x00000002 },
@ -153,6 +206,7 @@ static const KeycodeLabel FLAGS[] = {
{ "MENU", 0x00000040 },
{ "LAUNCHER", 0x00000080 },
{ "VIRTUAL", 0x00000100 },
{ "FUNCTION", 0x00000200 },
{ NULL, 0 }
};

View File

@ -157,9 +157,12 @@ public:
inline size_t size() const;
inline size_t length() const;
inline size_t bytes() const;
inline bool isEmpty() const;
inline const SharedBuffer* sharedBuffer() const;
void clear();
void setTo(const String8& other);
status_t setTo(const char* other);
status_t setTo(const char* other, size_t numChars);
@ -345,6 +348,11 @@ inline size_t String8::size() const
return length();
}
inline bool String8::isEmpty() const
{
return length() == 0;
}
inline size_t String8::bytes() const
{
return SharedBuffer::sizeFromData(mString)-1;

View File

@ -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 = '_';
// Configure the keymap for the device.
configureKeyMap(device);
// 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);
}
// 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

View File

@ -70,32 +70,15 @@ static inline const char* toString(bool value) {
return value ? "true" : "false";
}
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;
case AKEYCODE_ALT_RIGHT:
mask = AMETA_ALT_RIGHT_ON;
break;
case AKEYCODE_SHIFT_LEFT:
mask = AMETA_SHIFT_LEFT_ON;
break;
case AKEYCODE_SHIFT_RIGHT:
mask = AMETA_SHIFT_RIGHT_ON;
break;
case AKEYCODE_SYM:
mask = AMETA_SYM_ON;
break;
default:
return oldMetaState;
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);
}
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;
}
@ -104,9 +87,58 @@ int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
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:
return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState);
case AKEYCODE_ALT_RIGHT:
return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState);
case AKEYCODE_SHIFT_LEFT:
return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState);
case AKEYCODE_SHIFT_RIGHT:
return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState);
case AKEYCODE_SYM:
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;
}
}
static const int32_t keyCodeRotationMap[][4] = {
// key codes enumerated counter-clockwise with the original (unrotated) key first
// no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation
@ -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 ---

View File

@ -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*

View File

@ -292,6 +292,11 @@ String8::~String8()
SharedBuffer::bufferFromData(mString)->release();
}
void String8::clear() {
SharedBuffer::bufferFromData(mString)->release();
mString = getEmptyString();
}
void String8::setTo(const String8& other)
{
SharedBuffer::bufferFromData(other.mString)->acquire();