OSDN Git Service

Add Dvorak keyboard layout.
authorJeff Brown <jeffbrown@google.com>
Wed, 18 Apr 2012 01:50:05 +0000 (18:50 -0700)
committerJeff Brown <jeffbrown@google.com>
Wed, 18 Apr 2012 01:50:05 +0000 (18:50 -0700)
Added support for mapping both scan codes and HID usages to
KeyLayoutMap and KeyCharacterMap.  Keyboard overlays can
now influence how key events are mapped to key codes.

Bug: 6110399
Change-Id: I6619fd2d3e1337c55928f89869dbc45b535c7ccf

include/androidfw/KeyCharacterMap.h
libs/androidfw/KeyCharacterMap.cpp
libs/androidfw/KeyLayoutMap.cpp
packages/InputDevices/res/raw/keyboard_layout_english_us_dvorak.kcm
services/input/EventHub.cpp
services/input/EventHub.h

index e0e6ffa..8db5781 100644 (file)
@@ -120,6 +120,10 @@ public:
     bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
             Vector<KeyEvent>& outEvents) const;
 
+    /* Maps a scan code and usage code to a key code, in case this key map overrides
+     * the mapping in some way. */
+    status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const;
+
 #if HAVE_ANDROID_OS
     /* Reads a key map from a parcel. */
     static sp<KeyCharacterMap> readFromParcel(Parcel* parcel);
@@ -198,6 +202,8 @@ private:
 
     private:
         status_t parseType();
+        status_t parseMap();
+        status_t parseMapKey();
         status_t parseKey();
         status_t parseKeyProperty();
         status_t parseModifier(const String8& token, int32_t* outMetaState);
@@ -209,6 +215,9 @@ private:
     KeyedVector<int32_t, Key*> mKeys;
     int mType;
 
+    KeyedVector<int32_t, int32_t> mKeysByScanCode;
+    KeyedVector<int32_t, int32_t> mKeysByUsageCode;
+
     KeyCharacterMap();
     KeyCharacterMap(const KeyCharacterMap& other);
 
index 66fdfd7..c8f9439 100644 (file)
@@ -90,7 +90,8 @@ KeyCharacterMap::KeyCharacterMap() :
 }
 
 KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) :
-    RefBase(), mType(other.mType) {
+    RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode),
+    mKeysByUsageCode(other.mKeysByUsageCode) {
     for (size_t i = 0; i < other.mKeys.size(); i++) {
         mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i)));
     }
@@ -180,6 +181,16 @@ sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base,
             map->mKeys.add(keyCode, new Key(*key));
         }
     }
+
+    for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) {
+        map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i),
+                overlay->mKeysByScanCode.valueAt(i));
+    }
+
+    for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) {
+        map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i),
+                overlay->mKeysByUsageCode.valueAt(i));
+    }
     return map;
 }
 
@@ -315,6 +326,37 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t
     return true;
 }
 
+status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
+    if (usageCode) {
+        ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
+        if (index >= 0) {
+#if DEBUG_MAPPING
+    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
+            scanCode, usageCode, *outKeyCode);
+#endif
+            *outKeyCode = mKeysByUsageCode.valueAt(index);
+            return OK;
+        }
+    }
+    if (scanCode) {
+        ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
+        if (index >= 0) {
+#if DEBUG_MAPPING
+    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
+            scanCode, usageCode, *outKeyCode);
+#endif
+            *outKeyCode = mKeysByScanCode.valueAt(index);
+            return OK;
+        }
+    }
+
+#if DEBUG_MAPPING
+        ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
+#endif
+    *outKeyCode = AKEYCODE_UNKNOWN;
+    return NAME_NOT_FOUND;
+}
+
 bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
     ssize_t index = mKeys.indexOfKey(keyCode);
     if (index >= 0) {
@@ -616,6 +658,10 @@ status_t KeyCharacterMap::Parser::parse() {
                     mTokenizer->skipDelimiters(WHITESPACE);
                     status_t status = parseType();
                     if (status) return status;
+                } else if (keywordToken == "map") {
+                    mTokenizer->skipDelimiters(WHITESPACE);
+                    status_t status = parseMap();
+                    if (status) return status;
                 } else if (keywordToken == "key") {
                     mTokenizer->skipDelimiters(WHITESPACE);
                     status_t status = parseKey();
@@ -710,6 +756,58 @@ status_t KeyCharacterMap::Parser::parseType() {
     return NO_ERROR;
 }
 
+status_t KeyCharacterMap::Parser::parseMap() {
+    String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
+    if (keywordToken == "key") {
+        mTokenizer->skipDelimiters(WHITESPACE);
+        return parseMapKey();
+    }
+    ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
+            keywordToken.string());
+    return BAD_VALUE;
+}
+
+status_t KeyCharacterMap::Parser::parseMapKey() {
+    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
+    bool mapUsage = false;
+    if (codeToken == "usage") {
+        mapUsage = true;
+        mTokenizer->skipDelimiters(WHITESPACE);
+        codeToken = mTokenizer->nextToken(WHITESPACE);
+    }
+
+    char* end;
+    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
+    if (*end) {
+        ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
+                mapUsage ? "usage" : "scan code", codeToken.string());
+        return BAD_VALUE;
+    }
+    KeyedVector<int32_t, int32_t>& map =
+            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
+    if (map.indexOfKey(code) >= 0) {
+        ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
+                mapUsage ? "usage" : "scan code", codeToken.string());
+        return BAD_VALUE;
+    }
+
+    mTokenizer->skipDelimiters(WHITESPACE);
+    String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
+    int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
+    if (!keyCode) {
+        ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
+                keyCodeToken.string());
+        return BAD_VALUE;
+    }
+
+#if DEBUG_PARSER
+    ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
+            mapUsage ? "usage" : "scan code", code, keyCode);
+#endif
+    map.add(code, keyCode);
+    return NO_ERROR;
+}
+
 status_t KeyCharacterMap::Parser::parseKey() {
     String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
     int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
index a7c2199..2db19c5 100644 (file)
@@ -199,17 +199,26 @@ status_t KeyLayoutMap::Parser::parse() {
 }
 
 status_t KeyLayoutMap::Parser::parseKey() {
-    String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
+    String8 codeToken = mTokenizer->nextToken(WHITESPACE);
+    bool mapUsage = false;
+    if (codeToken == "usage") {
+        mapUsage = true;
+        mTokenizer->skipDelimiters(WHITESPACE);
+        codeToken = mTokenizer->nextToken(WHITESPACE);
+    }
+
     char* end;
-    int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
+    int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
     if (*end) {
-        ALOGE("%s: Expected key scan code number, got '%s'.", mTokenizer->getLocation().string(),
-                scanCodeToken.string());
+        ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
+                mapUsage ? "usage" : "scan code", codeToken.string());
         return BAD_VALUE;
     }
-    if (mMap->mKeysByScanCode.indexOfKey(scanCode) >= 0) {
-        ALOGE("%s: Duplicate entry for key scan code '%s'.", mTokenizer->getLocation().string(),
-                scanCodeToken.string());
+    KeyedVector<int32_t, Key>& map =
+            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
+    if (map.indexOfKey(code) >= 0) {
+        ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
+                mapUsage ? "usage" : "scan code", codeToken.string());
         return BAD_VALUE;
     }
 
@@ -243,12 +252,13 @@ status_t KeyLayoutMap::Parser::parseKey() {
     }
 
 #if DEBUG_PARSER
-    ALOGD("Parsed key: scanCode=%d, keyCode=%d, flags=0x%08x.", scanCode, keyCode, flags);
+    ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
+            mapUsage ? "usage" : "scan code", code, keyCode, flags);
 #endif
     Key key;
     key.keyCode = keyCode;
     key.flags = flags;
-    mMap->mKeysByScanCode.add(scanCode, key);
+    map.add(code, key);
     return NO_ERROR;
 }
 
index b5bf2ef..a2d110e 100644 (file)
 
 type OVERLAY
 
-# Test
-key A {
-    label:                              'X'
-    base:                               'x'
-    shift, capslock:                    'X'
-    ctrl, alt, meta:                    none
-}
+map key 12 LEFT_BRACKET
+map key 13 RIGHT_BRACKET
+map key 16 APOSTROPHE
+map key 17 COMMA
+map key 18 PERIOD
+map key 19 P
+map key 20 Y
+map key 21 F
+map key 22 G
+map key 23 C
+map key 24 R
+map key 25 L
+map key 26 SLASH
+map key 27 EQUALS
+map key 30 A
+map key 31 O
+map key 32 E
+map key 33 U
+map key 34 I
+map key 35 D
+map key 36 H
+map key 37 T
+map key 38 N
+map key 39 S
+map key 40 MINUS
+map key 44 SEMICOLON
+map key 45 Q
+map key 46 J
+map key 47 K
+map key 48 X
+map key 49 B
+map key 50 M
+map key 51 W
+map key 52 V
+map key 53 Z
index b788e16..326dc32 100644 (file)
@@ -443,11 +443,22 @@ status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
 
-    if (device && device->keyMap.haveKeyLayout()) {
-        status_t err = device->keyMap.keyLayoutMap->mapKey(
-                scanCode, usageCode, outKeycode, outFlags);
-        if (err == NO_ERROR) {
-            return NO_ERROR;
+    if (device) {
+        // Check the key character map first.
+        sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
+        if (kcm != NULL) {
+            if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
+                *outFlags = 0;
+                return NO_ERROR;
+            }
+        }
+
+        // Check the key layout next.
+        if (device->keyMap.haveKeyLayout()) {
+            if (!device->keyMap.keyLayoutMap->mapKey(
+                    scanCode, usageCode, outKeycode, outFlags)) {
+                return NO_ERROR;
+            }
         }
     }
 
@@ -531,10 +542,7 @@ sp<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device) {
-        if (device->combinedKeyMap != NULL) {
-            return device->combinedKeyMap;
-        }
-        return device->keyMap.keyCharacterMap;
+        return device->getKeyCharacterMap();
     }
     return NULL;
 }
index f885f4d..afc12ef 100644 (file)
@@ -335,6 +335,13 @@ private:
         void close();
 
         inline bool isVirtual() const { return fd < 0; }
+
+        const sp<KeyCharacterMap>& getKeyCharacterMap() const {
+            if (combinedKeyMap != NULL) {
+                return combinedKeyMap;
+            }
+            return keyMap.keyCharacterMap;
+        }
     };
 
     status_t openDeviceLocked(const char *devicePath);