summaryrefslogtreecommitdiffstats
path: root/libs/ui/EventHub.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ui/EventHub.cpp')
-rw-r--r--libs/ui/EventHub.cpp210
1 files changed, 168 insertions, 42 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