diff options
Diffstat (limited to 'libs/ui/Keyboard.cpp')
-rw-r--r-- | libs/ui/Keyboard.cpp | 224 |
1 files changed, 144 insertions, 80 deletions
diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp index de76e25..6faa600 100644 --- a/libs/ui/Keyboard.cpp +++ b/libs/ui/Keyboard.cpp @@ -22,102 +22,173 @@ #include <ui/Keyboard.h> #include <ui/KeycodeLabels.h> +#include <ui/KeyLayoutMap.h> +#include <ui/KeyCharacterMap.h> #include <utils/Errors.h> #include <utils/Log.h> #include <cutils/properties.h> namespace android { -static void selectKeyMap(KeyMapInfo& keyMapInfo, const String8& keyMapName, bool defaultKeyMap) { - if (keyMapInfo.keyMapName.isEmpty()) { - keyMapInfo.keyMapName.setTo(keyMapName); - keyMapInfo.isDefaultKeyMap = defaultKeyMap; - } +// --- KeyMap --- + +KeyMap::KeyMap() : + keyLayoutMap(NULL), keyCharacterMap(NULL) { +} + +KeyMap::~KeyMap() { + delete keyLayoutMap; + delete keyCharacterMap; } -static bool probeKeyMap(KeyMapInfo& keyMapInfo, const String8& keyMapName, bool defaultKeyMap) { - const char* root = getenv("ANDROID_ROOT"); +status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, + const PropertyMap* deviceConfiguration) { + // Use the configured key layout if available. + if (deviceConfiguration) { + String8 keyLayoutName; + if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), + keyLayoutName)) { + status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName); + if (status == NAME_NOT_FOUND) { + LOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " + "it was not found.", + deviceIdenfifier.name.string(), keyLayoutName.string()); + } + } - // TODO Consider also looking somewhere in a writeable partition like /data for a - // custom keymap supplied by the user for this device. - bool haveKeyLayout = !keyMapInfo.keyLayoutFile.isEmpty(); - if (!haveKeyLayout) { - keyMapInfo.keyLayoutFile.setTo(root); - keyMapInfo.keyLayoutFile.append("/usr/keylayout/"); - keyMapInfo.keyLayoutFile.append(keyMapName); - keyMapInfo.keyLayoutFile.append(".kl"); - if (access(keyMapInfo.keyLayoutFile.string(), R_OK)) { - keyMapInfo.keyLayoutFile.clear(); - } else { - haveKeyLayout = true; + String8 keyCharacterMapName; + if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), + keyCharacterMapName)) { + status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName); + if (status == NAME_NOT_FOUND) { + LOGE("Configuration for keyboard device '%s' requested keyboard character " + "map '%s' but it was not found.", + deviceIdenfifier.name.string(), keyLayoutName.string()); + } } - } - bool haveKeyCharacterMap = !keyMapInfo.keyCharacterMapFile.isEmpty(); - if (!haveKeyCharacterMap) { - keyMapInfo.keyCharacterMapFile.setTo(root); - keyMapInfo.keyCharacterMapFile.append("/usr/keychars/"); - keyMapInfo.keyCharacterMapFile.append(keyMapName); - keyMapInfo.keyCharacterMapFile.append(".kcm"); - if (access(keyMapInfo.keyCharacterMapFile.string(), R_OK)) { - keyMapInfo.keyCharacterMapFile.clear(); - } else { - haveKeyCharacterMap = true; + if (isComplete()) { + return OK; } } - if (haveKeyLayout || haveKeyCharacterMap) { - selectKeyMap(keyMapInfo, keyMapName, defaultKeyMap); + // Try searching by device identifier. + if (probeKeyMap(deviceIdenfifier, String8::empty())) { + return OK; + } + + // Fall back on the Generic key map. + // TODO Apply some additional heuristics here to figure out what kind of + // generic key map to use (US English, etc.) for typical external keyboards. + if (probeKeyMap(deviceIdenfifier, String8("Generic"))) { + return OK; + } + + // Try the Virtual key map as a last resort. + if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) { + return OK; } - return haveKeyLayout && haveKeyCharacterMap; + + // Give up! + LOGE("Could not determine key map for device '%s' and no default key maps were found!", + deviceIdenfifier.name.string()); + return NAME_NOT_FOUND; } -status_t resolveKeyMap(const String8& deviceName, KeyMapInfo& outKeyMapInfo) { - // As an initial key map name, try using the device name. - String8 keyMapName(deviceName); - char* p = keyMapName.lockBuffer(keyMapName.size()); - while (*p) { - if (*p == ' ') *p = '_'; - p++; +bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, + const String8& keyMapName) { + if (!haveKeyLayout()) { + loadKeyLayout(deviceIdentifier, keyMapName); } - keyMapName.unlockBuffer(); + if (!haveKeyCharacterMap()) { + loadKeyCharacterMap(deviceIdentifier, keyMapName); + } + return isComplete(); +} - if (probeKeyMap(outKeyMapInfo, keyMapName, false)) return OK; +status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, + const String8& name) { + String8 path(getPath(deviceIdentifier, name, + INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT)); + if (path.isEmpty()) { + return NAME_NOT_FOUND; + } - // TODO Consider allowing the user to configure a specific key map somehow. + KeyLayoutMap* map; + status_t status = KeyLayoutMap::load(path, &map); + if (status) { + return status; + } - // 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(outKeyMapInfo, keyMapName, true)) return OK; + keyLayoutFile.setTo(path); + keyLayoutMap = map; + return OK; +} - // Give up! - keyMapName.setTo("unknown"); - selectKeyMap(outKeyMapInfo, keyMapName, true); - LOGE("Could not determine key map for device '%s'.", deviceName.string()); - return NAME_NOT_FOUND; +status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier, + const String8& name) { + String8 path(getPath(deviceIdentifier, name, + INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP)); + if (path.isEmpty()) { + return NAME_NOT_FOUND; + } + + KeyCharacterMap* map; + status_t status = KeyCharacterMap::load(path, &map); + if (status) { + return status; + } + + keyCharacterMapFile.setTo(path); + keyCharacterMap = map; + return OK; } -void setKeyboardProperties(int32_t deviceId, const String8& deviceName, - const KeyMapInfo& keyMapInfo) { +String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier, + const String8& name, InputDeviceConfigurationFileType type) { + return name.isEmpty() + ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type) + : getInputDeviceConfigurationFilePathByName(name, type); +} + + +// --- Global functions --- + +bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, + const PropertyMap* deviceConfiguration, const KeyMap* keyMap) { + if (!keyMap->haveKeyCharacterMap() + || keyMap->keyCharacterMap->getKeyboardType() + == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) { + return false; + } + + if (deviceConfiguration) { + bool builtIn = false; + if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn) + && builtIn) { + return true; + } + } + + return strstr(deviceIdentifier.name.string(), "-keypad"); +} + +void setKeyboardProperties(int32_t deviceId, + const InputDeviceIdentifier& deviceIdentifier, + const String8& keyLayoutFile, const String8& keyCharacterMapFile) { char propName[PROPERTY_KEY_MAX]; snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId); - property_set(propName, deviceName.string()); - snprintf(propName, sizeof(propName), "hw.keyboards.%u.keymap", deviceId); - property_set(propName, keyMapInfo.keyMapName.string()); + property_set(propName, deviceIdentifier.name.string()); snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId); - property_set(propName, keyMapInfo.keyLayoutFile.string()); + property_set(propName, keyLayoutFile.string()); snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId); - property_set(propName, keyMapInfo.keyCharacterMapFile.string()); + property_set(propName, keyCharacterMapFile.string()); } void clearKeyboardProperties(int32_t deviceId) { char propName[PROPERTY_KEY_MAX]; snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId); property_set(propName, ""); - snprintf(propName, sizeof(propName), "hw.keyboards.%u.keymap", deviceId); - property_set(propName, ""); snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId); property_set(propName, ""); snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId); @@ -125,31 +196,24 @@ void clearKeyboardProperties(int32_t deviceId) { } status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFile) { - char propName[PROPERTY_KEY_MAX]; - char fn[PROPERTY_VALUE_MAX]; - snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId); - if (property_get(propName, fn, "") > 0) { - outKeyCharacterMapFile.setTo(fn); - return OK; - } - - const char* root = getenv("ANDROID_ROOT"); - char path[PATH_MAX]; - if (deviceId == DEVICE_ID_VIRTUAL_KEYBOARD) { - snprintf(path, sizeof(path), "%s/usr/keychars/Virtual.kcm", root); - if (!access(path, R_OK)) { - outKeyCharacterMapFile.setTo(path); + if (deviceId != DEVICE_ID_VIRTUAL_KEYBOARD) { + char propName[PROPERTY_KEY_MAX]; + char fn[PROPERTY_VALUE_MAX]; + snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId); + if (property_get(propName, fn, "") > 0) { + outKeyCharacterMapFile.setTo(fn); return OK; } } - snprintf(path, sizeof(path), "%s/usr/keychars/Generic.kcm", root); - if (!access(path, R_OK)) { - outKeyCharacterMapFile.setTo(path); + // Default to Virtual since the keyboard does not appear to be installed. + outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePathByName(String8("Virtual"), + INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP)); + if (!outKeyCharacterMapFile.isEmpty()) { return OK; } - LOGE("Can't find any key character map files (also tried %s)", path); + LOGE("Can't find any key character map files including the Virtual key map!"); return NAME_NOT_FOUND; } |