1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gonk/libui/Keyboard.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,298 @@ 1.4 +/* 1.5 + * Copyright (C) 2010 The Android Open Source Project 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +#define LOG_TAG "Keyboard" 1.21 +#include "cutils_log.h" 1.22 + 1.23 +#include <stdlib.h> 1.24 +#include <unistd.h> 1.25 +#include <limits.h> 1.26 + 1.27 +#include "Keyboard.h" 1.28 +#include "KeycodeLabels.h" 1.29 +#include "KeyLayoutMap.h" 1.30 +#include "KeyCharacterMap.h" 1.31 +#include "InputDevice.h" 1.32 +#include <utils/Errors.h> 1.33 +#include <cutils/properties.h> 1.34 + 1.35 +namespace android { 1.36 + 1.37 +// --- KeyMap --- 1.38 + 1.39 +KeyMap::KeyMap() { 1.40 +} 1.41 + 1.42 +KeyMap::~KeyMap() { 1.43 +} 1.44 + 1.45 +status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, 1.46 + const PropertyMap* deviceConfiguration) { 1.47 + // Use the configured key layout if available. 1.48 + if (deviceConfiguration) { 1.49 + String8 keyLayoutName; 1.50 + if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), 1.51 + keyLayoutName)) { 1.52 + status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName); 1.53 + if (status == NAME_NOT_FOUND) { 1.54 + ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " 1.55 + "it was not found.", 1.56 + deviceIdenfifier.name.string(), keyLayoutName.string()); 1.57 + } 1.58 + } 1.59 + 1.60 + String8 keyCharacterMapName; 1.61 + if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), 1.62 + keyCharacterMapName)) { 1.63 + status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName); 1.64 + if (status == NAME_NOT_FOUND) { 1.65 + ALOGE("Configuration for keyboard device '%s' requested keyboard character " 1.66 + "map '%s' but it was not found.", 1.67 + deviceIdenfifier.name.string(), keyLayoutName.string()); 1.68 + } 1.69 + } 1.70 + 1.71 + if (isComplete()) { 1.72 + return OK; 1.73 + } 1.74 + } 1.75 + 1.76 + // Try searching by device identifier. 1.77 + if (probeKeyMap(deviceIdenfifier, String8::empty())) { 1.78 + return OK; 1.79 + } 1.80 + 1.81 + // Fall back on the Generic key map. 1.82 + // TODO Apply some additional heuristics here to figure out what kind of 1.83 + // generic key map to use (US English, etc.) for typical external keyboards. 1.84 + if (probeKeyMap(deviceIdenfifier, String8("Generic"))) { 1.85 + return OK; 1.86 + } 1.87 + 1.88 + // Try the Virtual key map as a last resort. 1.89 + if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) { 1.90 + return OK; 1.91 + } 1.92 + 1.93 + // Give up! 1.94 + ALOGE("Could not determine key map for device '%s' and no default key maps were found!", 1.95 + deviceIdenfifier.name.string()); 1.96 + return NAME_NOT_FOUND; 1.97 +} 1.98 + 1.99 +bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, 1.100 + const String8& keyMapName) { 1.101 + if (!haveKeyLayout()) { 1.102 + loadKeyLayout(deviceIdentifier, keyMapName); 1.103 + } 1.104 + if (!haveKeyCharacterMap()) { 1.105 + loadKeyCharacterMap(deviceIdentifier, keyMapName); 1.106 + } 1.107 + return isComplete(); 1.108 +} 1.109 + 1.110 +status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, 1.111 + const String8& name) { 1.112 + String8 path(getPath(deviceIdentifier, name, 1.113 + INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT)); 1.114 + if (path.isEmpty()) { 1.115 + return NAME_NOT_FOUND; 1.116 + } 1.117 + 1.118 + status_t status = KeyLayoutMap::load(path, &keyLayoutMap); 1.119 + if (status) { 1.120 + return status; 1.121 + } 1.122 + 1.123 + keyLayoutFile.setTo(path); 1.124 + return OK; 1.125 +} 1.126 + 1.127 +status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier, 1.128 + const String8& name) { 1.129 + String8 path(getPath(deviceIdentifier, name, 1.130 + INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP)); 1.131 + if (path.isEmpty()) { 1.132 + return NAME_NOT_FOUND; 1.133 + } 1.134 + 1.135 + status_t status = KeyCharacterMap::load(path, 1.136 + KeyCharacterMap::FORMAT_BASE, &keyCharacterMap); 1.137 + if (status) { 1.138 + return status; 1.139 + } 1.140 + 1.141 + keyCharacterMapFile.setTo(path); 1.142 + return OK; 1.143 +} 1.144 + 1.145 +String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier, 1.146 + const String8& name, InputDeviceConfigurationFileType type) { 1.147 + return name.isEmpty() 1.148 + ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type) 1.149 + : getInputDeviceConfigurationFilePathByName(name, type); 1.150 +} 1.151 + 1.152 + 1.153 +// --- Global functions --- 1.154 + 1.155 +bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, 1.156 + const PropertyMap* deviceConfiguration, const KeyMap* keyMap) { 1.157 + if (!keyMap->haveKeyCharacterMap() 1.158 + || keyMap->keyCharacterMap->getKeyboardType() 1.159 + == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) { 1.160 + return false; 1.161 + } 1.162 + 1.163 + if (deviceConfiguration) { 1.164 + bool builtIn = false; 1.165 + if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn) 1.166 + && builtIn) { 1.167 + return true; 1.168 + } 1.169 + } 1.170 + 1.171 + return strstr(deviceIdentifier.name.string(), "-keypad"); 1.172 +} 1.173 + 1.174 +static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) { 1.175 + while (list->literal) { 1.176 + if (strcmp(literal, list->literal) == 0) { 1.177 + return list->value; 1.178 + } 1.179 + list++; 1.180 + } 1.181 + return list->value; 1.182 +} 1.183 + 1.184 +static const char* lookupLabelByValue(int value, const KeycodeLabel *list) { 1.185 + while (list->literal) { 1.186 + if (list->value == value) { 1.187 + return list->literal; 1.188 + } 1.189 + list++; 1.190 + } 1.191 + return NULL; 1.192 +} 1.193 + 1.194 +int32_t getKeyCodeByLabel(const char* label) { 1.195 + return int32_t(lookupValueByLabel(label, KEYCODES)); 1.196 +} 1.197 + 1.198 +uint32_t getKeyFlagByLabel(const char* label) { 1.199 + return uint32_t(lookupValueByLabel(label, FLAGS)); 1.200 +} 1.201 + 1.202 +int32_t getAxisByLabel(const char* label) { 1.203 + return int32_t(lookupValueByLabel(label, AXES)); 1.204 +} 1.205 + 1.206 +const char* getAxisLabel(int32_t axisId) { 1.207 + return lookupLabelByValue(axisId, AXES); 1.208 +} 1.209 + 1.210 +static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) { 1.211 + int32_t newMetaState; 1.212 + if (down) { 1.213 + newMetaState = oldMetaState | mask; 1.214 + } else { 1.215 + newMetaState = oldMetaState & 1.216 + ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON); 1.217 + } 1.218 + 1.219 + if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { 1.220 + newMetaState |= AMETA_ALT_ON; 1.221 + } 1.222 + 1.223 + if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) { 1.224 + newMetaState |= AMETA_SHIFT_ON; 1.225 + } 1.226 + 1.227 + if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { 1.228 + newMetaState |= AMETA_CTRL_ON; 1.229 + } 1.230 + 1.231 + if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { 1.232 + newMetaState |= AMETA_META_ON; 1.233 + } 1.234 + return newMetaState; 1.235 +} 1.236 + 1.237 +static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) { 1.238 + if (down) { 1.239 + return oldMetaState; 1.240 + } else { 1.241 + return oldMetaState ^ mask; 1.242 + } 1.243 +} 1.244 + 1.245 +int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { 1.246 + int32_t mask; 1.247 + switch (keyCode) { 1.248 + case AKEYCODE_ALT_LEFT: 1.249 + return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState); 1.250 + case AKEYCODE_ALT_RIGHT: 1.251 + return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState); 1.252 + case AKEYCODE_SHIFT_LEFT: 1.253 + return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState); 1.254 + case AKEYCODE_SHIFT_RIGHT: 1.255 + return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState); 1.256 + case AKEYCODE_SYM: 1.257 + return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState); 1.258 + case AKEYCODE_FUNCTION: 1.259 + return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState); 1.260 + case AKEYCODE_CTRL_LEFT: 1.261 + return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState); 1.262 + case AKEYCODE_CTRL_RIGHT: 1.263 + return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState); 1.264 + case AKEYCODE_META_LEFT: 1.265 + return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState); 1.266 + case AKEYCODE_META_RIGHT: 1.267 + return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState); 1.268 + case AKEYCODE_CAPS_LOCK: 1.269 + return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState); 1.270 + case AKEYCODE_NUM_LOCK: 1.271 + return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState); 1.272 + case AKEYCODE_SCROLL_LOCK: 1.273 + return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState); 1.274 + default: 1.275 + return oldMetaState; 1.276 + } 1.277 +} 1.278 + 1.279 +bool isMetaKey(int32_t keyCode) { 1.280 + switch (keyCode) { 1.281 + case AKEYCODE_ALT_LEFT: 1.282 + case AKEYCODE_ALT_RIGHT: 1.283 + case AKEYCODE_SHIFT_LEFT: 1.284 + case AKEYCODE_SHIFT_RIGHT: 1.285 + case AKEYCODE_SYM: 1.286 + case AKEYCODE_FUNCTION: 1.287 + case AKEYCODE_CTRL_LEFT: 1.288 + case AKEYCODE_CTRL_RIGHT: 1.289 + case AKEYCODE_META_LEFT: 1.290 + case AKEYCODE_META_RIGHT: 1.291 + case AKEYCODE_CAPS_LOCK: 1.292 + case AKEYCODE_NUM_LOCK: 1.293 + case AKEYCODE_SCROLL_LOCK: 1.294 + return true; 1.295 + default: 1.296 + return false; 1.297 + } 1.298 +} 1.299 + 1.300 + 1.301 +} // namespace android