diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index 6c798a64b..6c6c297f8 100644 --- a/include/ui/EventHub.h +++ b/include/ui/EventHub.h @@ -18,8 +18,11 @@ #ifndef _RUNTIME_EVENT_HUB_H #define _RUNTIME_EVENT_HUB_H -#include +#include #include +#include +#include +#include #include #include #include @@ -27,6 +30,7 @@ #include #include #include +#include #include @@ -59,8 +63,6 @@ struct pollfd; namespace android { -class KeyLayoutMap; - /* * A raw event as retrieved from the EventHub. */ @@ -194,6 +196,9 @@ public: 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 getVirtualKeyDefinitions(int32_t deviceId, + Vector& outVirtualKeys) const = 0; + virtual void dump(String8& dump) = 0; }; @@ -230,6 +235,9 @@ public: virtual bool hasLed(int32_t deviceId, int32_t led) const; virtual void setLedState(int32_t deviceId, int32_t led, bool on); + virtual void getVirtualKeyDefinitions(int32_t deviceId, + Vector& outVirtualKeys) const; + virtual void dump(String8& dump); protected: @@ -238,78 +246,80 @@ protected: private: bool openPlatformInput(void); - int openDevice(const char *device); - int closeDevice(const char *device); + int openDevice(const char *devicePath); + int closeDevice(const char *devicePath); int scanDir(const char *dirname); int readNotify(int nfd); status_t mError; - struct device_t { - const int32_t id; - const String8 path; - String8 name; - uint32_t classes; - uint8_t* keyBitmask; - KeyLayoutMap* layoutMap; - String8 configurationFile; - PropertyMap* configuration; - KeyMapInfo keyMapInfo; - int fd; - device_t* next; - - device_t(int32_t _id, const char* _path, const char* name); - ~device_t(); + struct Device { + Device* next; + + int fd; + const int32_t id; + const String8 path; + const InputDeviceIdentifier identifier; + + uint32_t classes; + uint8_t* keyBitmask; + String8 configurationFile; + PropertyMap* configuration; + VirtualKeyMap* virtualKeyMap; + KeyMap keyMap; + + Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier); + ~Device(); + + void close(); }; - device_t* getDeviceLocked(int32_t deviceId) const; - bool hasKeycodeLocked(device_t* device, int keycode) const; + Device* getDeviceLocked(int32_t deviceId) const; + bool hasKeycodeLocked(Device* 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, + int32_t getScanCodeStateLocked(Device* device, int32_t scanCode) const; + int32_t getKeyCodeStateLocked(Device* device, int32_t keyCode) const; + int32_t getSwitchStateLocked(Device* device, int32_t sw) const; + bool markSupportedKeyCodesLocked(Device* device, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const; - void loadConfiguration(device_t* device); - void configureKeyMap(device_t* device); - void setKeyboardProperties(device_t* device, bool firstKeyboard); - void clearKeyboardProperties(device_t* device, bool firstKeyboard); + void loadConfiguration(Device* device); + status_t loadVirtualKeyMap(Device* device); + status_t loadKeyMap(Device* device); + void setKeyboardProperties(Device* device, bool builtInKeyboard); + void clearKeyboardProperties(Device* device, bool builtInKeyboard); // Protect all internal state. - mutable Mutex mLock; - - bool mHaveFirstKeyboard; - int32_t mFirstKeyboardId; // the API is that the built-in keyboard is id 0, so map it - - struct device_ent { - device_t* device; - uint32_t seq; - }; - device_ent *mDevicesById; - int mNumDevicesById; - - device_t *mOpeningDevices; - device_t *mClosingDevices; - - device_t **mDevices; - struct pollfd *mFDs; - int mFDCount; + mutable Mutex mLock; - bool mOpened; - bool mNeedToSendFinishedDeviceScan; - List mExcludedDevices; + // The actual id of the built-in keyboard, or -1 if none. + // EventHub remaps the built-in keyboard to id 0 externally as required by the API. + int32_t mBuiltInKeyboardId; + + int32_t mNextDeviceId; + + // Parallel arrays of fds and devices. + // First index is reserved for inotify. + Vector mFds; + Vector mDevices; + + Device *mOpeningDevices; + Device *mClosingDevices; + + bool mOpened; + bool mNeedToSendFinishedDeviceScan; + List mExcludedDevices; // device ids that report particular switches. #ifdef EV_SW - int32_t mSwitches[SW_MAX + 1]; + int32_t mSwitches[SW_MAX + 1]; #endif static const int INPUT_BUFFER_SIZE = 64; struct input_event mInputBufferData[INPUT_BUFFER_SIZE]; - int32_t mInputBufferIndex; - int32_t mInputBufferCount; - int32_t mInputDeviceIndex; + size_t mInputBufferIndex; + size_t mInputBufferCount; + size_t mInputFdIndex; }; }; // namespace android diff --git a/include/ui/Input.h b/include/ui/Input.h index 4dc8f2a84..27f65bce8 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -497,6 +497,23 @@ private: KeyedVector mMotionRanges; }; +/* + * Identifies a device. + */ +struct InputDeviceIdentifier { + inline InputDeviceIdentifier() : + bus(0), vendor(0), product(0), version(0) { + } + + String8 name; + String8 location; + String8 uniqueId; + uint16_t bus; + uint16_t vendor; + uint16_t product; + uint16_t version; +}; + /* Types of input device configuration files. */ enum InputDeviceConfigurationFileType { INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */ @@ -505,13 +522,28 @@ enum InputDeviceConfigurationFileType { }; /* - * Get the path of an input device configuration file, if one is available. - * Spaces in the name are replaced with underscores. + * Gets the path of an input device configuration file, if one is available. * Considers both system provided and user installed configuration files. * + * The device identifier is used to construct several default configuration file + * names to try based on the device name, vendor, product, and version. + * * Returns an empty string if not found. */ -extern String8 getInputDeviceConfigurationFilePath( +extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( + const InputDeviceIdentifier& deviceIdentifier, + InputDeviceConfigurationFileType type); + +/* + * Gets the path of an input device configuration file, if one is available. + * Considers both system provided and user installed configuration files. + * + * The name is case-sensitive and is used to construct the filename to resolve. + * All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores. + * + * Returns an empty string if not found. + */ +extern String8 getInputDeviceConfigurationFilePathByName( const String8& name, InputDeviceConfigurationFileType type); } // namespace android diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h index cfceaab1f..8ec542194 100644 --- a/include/ui/InputReader.h +++ b/include/ui/InputReader.h @@ -35,17 +35,6 @@ namespace android { class InputDevice; class InputMapper; -/* Describes a virtual key. */ -struct VirtualKeyDefinition { - int32_t scanCode; - - // configured position data, specified in display coords - int32_t centerX; - int32_t centerY; - int32_t width; - int32_t height; -}; - /* * Input reader policy interface. @@ -86,10 +75,6 @@ public: */ virtual bool filterJumpyTouchEvents() = 0; - /* Gets the configured virtual key definitions for an input device. */ - virtual void getVirtualKeyDefinitions(const String8& deviceName, - Vector& outVirtualKeyDefinitions) = 0; - /* Gets the excluded device names for the platform. */ virtual void getExcludedDeviceNames(Vector& outExcludedDeviceNames) = 0; }; diff --git a/include/ui/Keyboard.h b/include/ui/Keyboard.h index 689607db5..50296e29b 100644 --- a/include/ui/Keyboard.h +++ b/include/ui/Keyboard.h @@ -33,30 +33,58 @@ enum { DEVICE_ID_VIRTUAL_KEYBOARD = -1, }; -struct KeyMapInfo { +class KeyLayoutMap; +class KeyCharacterMap; + +/** + * Loads the key layout map and key character map for a keyboard device. + */ +class KeyMap { +public: String8 keyLayoutFile; + KeyLayoutMap* keyLayoutMap; + String8 keyCharacterMapFile; - bool isDefaultKeyMap; + KeyCharacterMap* keyCharacterMap; - KeyMapInfo() : isDefaultKeyMap(false) { + KeyMap(); + ~KeyMap(); + + status_t load(const InputDeviceIdentifier& deviceIdenfier, + const PropertyMap* deviceConfiguration); + + inline bool haveKeyLayout() const { + return !keyLayoutFile.isEmpty(); } - bool isComplete() { - return !keyLayoutFile.isEmpty() && !keyCharacterMapFile.isEmpty(); + inline bool haveKeyCharacterMap() const { + return !keyCharacterMapFile.isEmpty(); } + + inline bool isComplete() const { + return haveKeyLayout() && haveKeyCharacterMap(); + } + +private: + bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name); + status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name); + status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier, + const String8& name); + String8 getPath(const InputDeviceIdentifier& deviceIdentifier, + const String8& name, InputDeviceConfigurationFileType type); }; /** - * Resolves the key map to use for a particular keyboard device. + * Returns true if the keyboard is eligible for use as a built-in keyboard. */ -extern status_t resolveKeyMap(const String8& deviceName, - const PropertyMap* deviceConfiguration, KeyMapInfo& outKeyMapInfo); +extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, + const PropertyMap* deviceConfiguration, const KeyMap* keyMap); /** * Sets keyboard system properties. */ -extern void setKeyboardProperties(int32_t deviceId, const String8& deviceName, - const KeyMapInfo& keyMapInfo); +extern void setKeyboardProperties(int32_t deviceId, const InputDeviceIdentifier& deviceIdentifier, + const String8& keyLayoutFile, const String8& keyCharacterMapFile); /** * Clears keyboard system properties. diff --git a/include/ui/VirtualKeyMap.h b/include/ui/VirtualKeyMap.h new file mode 100644 index 000000000..7813d9d03 --- /dev/null +++ b/include/ui/VirtualKeyMap.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UI_VIRTUAL_KEY_MAP_H +#define _UI_VIRTUAL_KEY_MAP_H + +#include + +#include +#include +#include +#include +#include +#include + +namespace android { + +/* Describes a virtual key. */ +struct VirtualKeyDefinition { + int32_t scanCode; + + // configured position data, specified in display coords + int32_t centerX; + int32_t centerY; + int32_t width; + int32_t height; +}; + + +/** + * Describes a collection of virtual keys on a touch screen in terms of + * virtual scan codes and hit rectangles. + */ +class VirtualKeyMap { +public: + ~VirtualKeyMap(); + + static status_t load(const String8& filename, VirtualKeyMap** outMap); + + inline const Vector& getVirtualKeys() const { + return mVirtualKeys; + } + +private: + class Parser { + VirtualKeyMap* mMap; + Tokenizer* mTokenizer; + + public: + Parser(VirtualKeyMap* map, Tokenizer* tokenizer); + ~Parser(); + status_t parse(); + + private: + bool consumeFieldDelimiterAndSkipWhitespace(); + bool parseNextIntField(int32_t* outValue); + }; + + Vector mVirtualKeys; + + VirtualKeyMap(); +}; + +} // namespace android + +#endif // _UI_KEY_CHARACTER_MAP_H diff --git a/include/utils/String8.h b/include/utils/String8.h index 6abfb0634..6b49ff5b4 100644 --- a/include/utils/String8.h +++ b/include/utils/String8.h @@ -47,7 +47,12 @@ public: explicit String8(const char32_t* o); explicit String8(const char32_t* o, size_t numChars); ~String8(); - + + static inline const String8 empty(); + + static String8 format(const char* fmt, ...) __attribute__((format (printf, 1, 2))); + static String8 formatV(const char* fmt, va_list args); + inline const char* string() const; inline size_t size() const; inline size_t length() const; @@ -229,6 +234,10 @@ inline int strictly_order_type(const String8& lhs, const String8& rhs) return compare_type(lhs, rhs) < 0; } +inline const String8 String8::empty() { + return String8(); +} + inline const char* String8::string() const { return mString; diff --git a/include/utils/Tokenizer.h b/include/utils/Tokenizer.h index 21e58e62c..c7db5fb9e 100644 --- a/include/utils/Tokenizer.h +++ b/include/utils/Tokenizer.h @@ -28,7 +28,7 @@ namespace android { * A simple tokenizer for loading and parsing ASCII text files line by line. */ class Tokenizer { - Tokenizer(const String8& filename, FileMap* fileMap, const char* buffer, size_t length); + Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length); public: ~Tokenizer(); @@ -110,7 +110,7 @@ private: String8 mFilename; FileMap* mFileMap; - const char* mBuffer; + char* mBuffer; size_t mLength; const char* mCurrent; diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index 5948e042c..d0e041ab4 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -21,6 +21,7 @@ commonSources:= \ Keyboard.cpp \ KeyLayoutMap.cpp \ KeyCharacterMap.cpp \ + VirtualKeyMap.cpp # For the host # ===================================================== diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index b312cda8a..8f4bac6c7 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -33,6 +33,8 @@ #include #include +#include +#include #include #include @@ -56,10 +58,6 @@ /* this macro computes the number of bytes needed to represent a bit array of the specified size */ #define sizeof_bit_array(bits) ((bits + 7) / 8) -#define ID_MASK 0x0000ffff -#define SEQ_MASK 0x7fff0000 -#define SEQ_SHIFT 16 - #ifndef ABS_MT_TOUCH_MAJOR #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ #endif @@ -72,6 +70,9 @@ #define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ #endif +// Fd at index 0 is always reserved for inotify +#define FIRST_ACTUAL_DEVICE_INDEX 1 + #define INDENT " " #define INDENT2 " " #define INDENT3 " " @@ -79,7 +80,7 @@ namespace android { static const char *WAKE_LOCK_ID = "KeyEvents"; -static const char *device_path = "/dev/input"; +static const char *DEVICE_PATH = "/dev/input"; /* return the larger integer */ static inline int max(int v1, int v2) @@ -91,63 +92,69 @@ static inline const char* toString(bool value) { return value ? "true" : "false"; } -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(NULL), configuration(NULL), fd(-1), next(NULL) { +// --- EventHub::Device --- + +EventHub::Device::Device(int fd, int32_t id, const String8& path, + const InputDeviceIdentifier& identifier) : + next(NULL), + fd(fd), id(id), path(path), identifier(identifier), + classes(0), keyBitmask(NULL), configuration(NULL), virtualKeyMap(NULL) { } -EventHub::device_t::~device_t() { - delete [] keyBitmask; - delete layoutMap; +EventHub::Device::~Device() { + close(); + delete[] keyBitmask; delete configuration; + delete virtualKeyMap; } -EventHub::EventHub(void) - : 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) - , mInputBufferIndex(0), mInputBufferCount(0), mInputDeviceIndex(0) -{ +void EventHub::Device::close() { + if (fd >= 0) { + ::close(fd); + fd = -1; + } +} + + +// --- EventHub --- + +EventHub::EventHub(void) : + mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1), + mOpeningDevices(0), mClosingDevices(0), + mOpened(false), mNeedToSendFinishedDeviceScan(false), + mInputBufferIndex(0), mInputBufferCount(0), mInputFdIndex(0) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); #ifdef EV_SW memset(mSwitches, 0, sizeof(mSwitches)); #endif } -/* - * Clean up. - */ -EventHub::~EventHub(void) -{ +EventHub::~EventHub(void) { release_wake_lock(WAKE_LOCK_ID); // we should free stuff here... } -status_t EventHub::errorCheck() const -{ +status_t EventHub::errorCheck() const { return mError; } -String8 EventHub::getDeviceName(int32_t deviceId) const -{ +String8 EventHub::getDeviceName(int32_t deviceId) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device == NULL) return String8(); - return device->name; + return device->identifier.name; } -uint32_t EventHub::getDeviceClasses(int32_t deviceId) const -{ +uint32_t EventHub::getDeviceClasses(int32_t deviceId) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device == NULL) return 0; return device->classes; } void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device && device->configuration) { *outConfiguration = *device->configuration; } else { @@ -160,14 +167,14 @@ status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, outAxisInfo->clear(); AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device == NULL) return -1; struct input_absinfo info; if(ioctl(device->fd, EVIOCGABS(axis), &info)) { LOGW("Error reading absolute controller %d for device %s fd %d\n", - axis, device->name.string(), device->fd); + axis, device->identifier.name.string(), device->fd); return -errno; } @@ -185,7 +192,7 @@ int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { if (scanCode >= 0 && scanCode <= KEY_MAX) { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device != NULL) { return getScanCodeStateLocked(device, scanCode); } @@ -193,7 +200,7 @@ int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { return AKEY_STATE_UNKNOWN; } -int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const { +int32_t EventHub::getScanCodeStateLocked(Device* device, int32_t scanCode) const { uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; memset(key_bitmask, 0, sizeof(key_bitmask)); if (ioctl(device->fd, @@ -206,20 +213,20 @@ int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) con int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device != NULL) { return getKeyCodeStateLocked(device, keyCode); } return AKEY_STATE_UNKNOWN; } -int32_t EventHub::getKeyCodeStateLocked(device_t* device, int32_t keyCode) const { - if (!device->layoutMap) { +int32_t EventHub::getKeyCodeStateLocked(Device* device, int32_t keyCode) const { + if (!device->keyMap.haveKeyLayout()) { return AKEY_STATE_UNKNOWN; } Vector scanCodes; - device->layoutMap->findScanCodes(keyCode, &scanCodes); + device->keyMap.keyLayoutMap->findScanCodes(keyCode, &scanCodes); uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; memset(key_bitmask, 0, sizeof(key_bitmask)); @@ -247,7 +254,7 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { if (sw >= 0 && sw <= SW_MAX) { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device != NULL) { return getSwitchStateLocked(device, sw); } @@ -256,7 +263,7 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { return AKEY_STATE_UNKNOWN; } -int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const { +int32_t EventHub::getSwitchStateLocked(Device* device, int32_t sw) const { uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)]; memset(sw_bitmask, 0, sizeof(sw_bitmask)); if (ioctl(device->fd, @@ -270,16 +277,16 @@ bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device != NULL) { return markSupportedKeyCodesLocked(device, numCodes, keyCodes, outFlags); } return false; } -bool EventHub::markSupportedKeyCodesLocked(device_t* device, size_t numCodes, +bool EventHub::markSupportedKeyCodesLocked(Device* device, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { - if (device->layoutMap == NULL || device->keyBitmask == NULL) { + if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { return false; } @@ -287,7 +294,7 @@ bool EventHub::markSupportedKeyCodesLocked(device_t* device, size_t numCodes, for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { scanCodes.clear(); - status_t err = device->layoutMap->findScanCodes(keyCodes[codeIndex], &scanCodes); + status_t err = device->keyMap.keyLayoutMap->findScanCodes(keyCodes[codeIndex], &scanCodes); if (! err) { // check the possible scan codes identified by the layout map against the // map of codes actually emitted by the driver @@ -306,20 +313,20 @@ status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); - if (device != NULL && device->layoutMap != NULL) { - status_t err = device->layoutMap->map(scancode, outKeycode, outFlags); + if (device && device->keyMap.haveKeyLayout()) { + status_t err = device->keyMap.keyLayoutMap->map(scancode, outKeycode, outFlags); if (err == NO_ERROR) { return NO_ERROR; } } - if (mHaveFirstKeyboard) { - device = getDeviceLocked(mFirstKeyboardId); + if (mBuiltInKeyboardId != -1) { + device = getDeviceLocked(mBuiltInKeyboardId); - if (device != NULL && device->layoutMap != NULL) { - status_t err = device->layoutMap->map(scancode, outKeycode, outFlags); + if (device && device->keyMap.haveKeyLayout()) { + status_t err = device->keyMap.keyLayoutMap->map(scancode, outKeycode, outFlags); if (err == NO_ERROR) { return NO_ERROR; } @@ -341,7 +348,7 @@ void EventHub::addExcludedDevice(const char* deviceName) bool EventHub::hasLed(int32_t deviceId, int32_t led) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device) { uint8_t bitmask[sizeof_bit_array(LED_MAX + 1)]; memset(bitmask, 0, sizeof(bitmask)); @@ -356,7 +363,7 @@ bool EventHub::hasLed(int32_t deviceId, int32_t led) const { void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device) { struct input_event ev; ev.time.tv_sec = 0; @@ -372,21 +379,33 @@ void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { } } -EventHub::device_t* EventHub::getDeviceLocked(int32_t deviceId) const -{ - if (deviceId == 0) deviceId = mFirstKeyboardId; - int32_t id = deviceId & ID_MASK; - if (id >= mNumDevicesById || id < 0) return NULL; - device_t* dev = mDevicesById[id].device; - if (dev == NULL) return NULL; - if (dev->id == deviceId) { - return dev; +void EventHub::getVirtualKeyDefinitions(int32_t deviceId, + Vector& outVirtualKeys) const { + outVirtualKeys.clear(); + + AutoMutex _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device && device->virtualKeyMap) { + outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys()); + } +} + +EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const { + if (deviceId == 0) { + deviceId = mBuiltInKeyboardId; + } + + size_t numDevices = mDevices.size(); + for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < numDevices; i++) { + Device* device = mDevices[i]; + if (device->id == deviceId) { + return device; + } } return NULL; } -bool EventHub::getEvent(RawEvent* outEvent) -{ +bool EventHub::getEvent(RawEvent* outEvent) { outEvent->deviceId = 0; outEvent->type = 0; outEvent->scanCode = 0; @@ -407,11 +426,11 @@ bool EventHub::getEvent(RawEvent* outEvent) for (;;) { // Report any devices that had last been added/removed. if (mClosingDevices != NULL) { - device_t* device = mClosingDevices; - LOGV("Reporting device closed: id=0x%x, name=%s\n", + Device* device = mClosingDevices; + LOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.string()); mClosingDevices = device->next; - if (device->id == mFirstKeyboardId) { + if (device->id == mBuiltInKeyboardId) { outEvent->deviceId = 0; } else { outEvent->deviceId = device->id; @@ -424,11 +443,11 @@ bool EventHub::getEvent(RawEvent* outEvent) } if (mOpeningDevices != NULL) { - device_t* device = mOpeningDevices; - LOGV("Reporting device opened: id=0x%x, name=%s\n", + Device* device = mOpeningDevices; + LOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.string()); mOpeningDevices = device->next; - if (device->id == mFirstKeyboardId) { + if (device->id == mBuiltInKeyboardId) { outEvent->deviceId = 0; } else { outEvent->deviceId = device->id; @@ -451,11 +470,11 @@ bool EventHub::getEvent(RawEvent* outEvent) // Consume buffered input events, if any. if (mInputBufferIndex < mInputBufferCount) { const struct input_event& iev = mInputBufferData[mInputBufferIndex++]; - const device_t* device = mDevices[mInputDeviceIndex]; + const Device* device = mDevices[mInputFdIndex]; LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(), (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value); - if (device->id == mFirstKeyboardId) { + if (device->id == mBuiltInKeyboardId) { outEvent->deviceId = 0; } else { outEvent->deviceId = device->id; @@ -465,8 +484,8 @@ bool EventHub::getEvent(RawEvent* outEvent) outEvent->flags = 0; if (iev.type == EV_KEY) { outEvent->keyCode = AKEYCODE_UNKNOWN; - if (device->layoutMap) { - status_t err = device->layoutMap->map(iev.code, + if (device->keyMap.haveKeyLayout()) { + status_t err = device->keyMap.keyLayoutMap->map(iev.code, &outEvent->keyCode, &outEvent->flags); LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n", iev.code, outEvent->keyCode, outEvent->flags, err); @@ -486,13 +505,13 @@ bool EventHub::getEvent(RawEvent* outEvent) // Finish reading all events from devices identified in previous poll(). // This code assumes that mInputDeviceIndex is initially 0 and that the // revents member of pollfd is initialized to 0 when the device is first added. - // Since mFDs[0] is used for inotify, we process regular events starting at index 1. - mInputDeviceIndex += 1; - if (mInputDeviceIndex >= mFDCount) { + // Since mFds[0] is used for inotify, we process regular events starting at index 1. + mInputFdIndex += 1; + if (mInputFdIndex >= mFds.size()) { break; } - const struct pollfd& pfd = mFDs[mInputDeviceIndex]; + const struct pollfd& pfd = mFds[mInputFdIndex]; if (pfd.revents & POLLIN) { int32_t readSize = read(pfd.fd, mInputBufferData, sizeof(struct input_event) * INPUT_BUFFER_SIZE); @@ -503,7 +522,7 @@ bool EventHub::getEvent(RawEvent* outEvent) } else if ((readSize % sizeof(struct input_event)) != 0) { LOGE("could not get event (wrong size: %d)", readSize); } else { - mInputBufferCount = readSize / sizeof(struct input_event); + mInputBufferCount = size_t(readSize) / sizeof(struct input_event); mInputBufferIndex = 0; } } @@ -512,14 +531,14 @@ bool EventHub::getEvent(RawEvent* outEvent) #if HAVE_INOTIFY // readNotify() will modify mFDs and mFDCount, so this must be done after // processing all other events. - if(mFDs[0].revents & POLLIN) { - readNotify(mFDs[0].fd); - mFDs[0].revents = 0; + if(mFds[0].revents & POLLIN) { + readNotify(mFds[0].fd); + mFds.editItemAt(0).revents = 0; continue; // report added or removed devices immediately } #endif - mInputDeviceIndex = 0; + mInputFdIndex = 0; // Poll for events. Mind the wake lock dance! // We hold a wake lock at all times except during poll(). This works due to some @@ -531,7 +550,7 @@ bool EventHub::getEvent(RawEvent* outEvent) // pending or currently being processed. release_wake_lock(WAKE_LOCK_ID); - int pollResult = poll(mFDs, mFDCount, -1); + int pollResult = poll(mFds.editArray(), mFds.size(), -1); acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); @@ -547,36 +566,37 @@ bool EventHub::getEvent(RawEvent* outEvent) /* * Open the platform-specific input device. */ -bool EventHub::openPlatformInput(void) -{ +bool EventHub::openPlatformInput(void) { /* * Open platform-specific input device(s). */ - int res; + int res, fd; - mFDCount = 1; - mFDs = (pollfd *)calloc(1, sizeof(mFDs[0])); - mDevices = (device_t **)calloc(1, sizeof(mDevices[0])); - mFDs[0].events = POLLIN; - mFDs[0].revents = 0; - mDevices[0] = NULL; #ifdef HAVE_INOTIFY - mFDs[0].fd = inotify_init(); - res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE); + fd = inotify_init(); + res = inotify_add_watch(fd, DEVICE_PATH, IN_DELETE | IN_CREATE); if(res < 0) { - LOGE("could not add watch for %s, %s\n", device_path, strerror(errno)); + LOGE("could not add watch for %s, %s\n", DEVICE_PATH, strerror(errno)); } #else /* * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd. * We allocate space for it and set it to something invalid. */ - mFDs[0].fd = -1; + fd = -1; #endif - res = scanDir(device_path); + // Reserve fd index 0 for inotify. + struct pollfd pollfd; + pollfd.fd = fd; + pollfd.events = POLLIN; + pollfd.revents = 0; + mFds.push(pollfd); + mDevices.push(NULL); + + res = scanDir(DEVICE_PATH); if(res < 0) { - LOGE("scan dir failed for %s\n", device_path); + LOGE("scan dir failed for %s\n", DEVICE_PATH); } return true; @@ -604,129 +624,102 @@ static const int32_t GAMEPAD_KEYCODES[] = { AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE }; -int EventHub::openDevice(const char *deviceName) { - int version; - int fd; - struct pollfd *new_mFDs; - device_t **new_devices; - char **new_device_names; - char name[80]; - char location[80]; - char idstr[80]; - struct input_id id; +int EventHub::openDevice(const char *devicePath) { + char buffer[80]; - LOGV("Opening device: %s", deviceName); + LOGV("Opening device: %s", devicePath); AutoMutex _l(mLock); - fd = open(deviceName, O_RDWR); + int fd = open(devicePath, O_RDWR); if(fd < 0) { - LOGE("could not open %s, %s\n", deviceName, strerror(errno)); + LOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; } - if(ioctl(fd, EVIOCGVERSION, &version)) { - LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno)); - return -1; - } - if(ioctl(fd, EVIOCGID, &id)) { - LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno)); - return -1; - } - name[sizeof(name) - 1] = '\0'; - location[sizeof(location) - 1] = '\0'; - idstr[sizeof(idstr) - 1] = '\0'; - if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { - //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno)); - name[0] = '\0'; + InputDeviceIdentifier identifier; + + // Get device name. + if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { + //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno)); + } else { + buffer[sizeof(buffer) - 1] = '\0'; + identifier.name.setTo(buffer); } - // check to see if the device is on our excluded list + // Check to see if the device is on our excluded list List::iterator iter = mExcludedDevices.begin(); List::iterator end = mExcludedDevices.end(); for ( ; iter != end; iter++) { const char* test = *iter; - if (strcmp(name, test) == 0) { - LOGI("ignoring event id %s driver %s\n", deviceName, test); + if (identifier.name == test) { + LOGI("ignoring event id %s driver %s\n", devicePath, test); close(fd); return -1; } } - if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) { - //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno)); - location[0] = '\0'; - } - if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) { - //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno)); - idstr[0] = '\0'; + // Get device driver version. + int driverVersion; + if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { + LOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); + close(fd); + return -1; } + // Get device identifier. + struct input_id inputId; + if(ioctl(fd, EVIOCGID, &inputId)) { + LOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); + close(fd); + return -1; + } + identifier.bus = inputId.bustype; + identifier.product = inputId.product; + identifier.vendor = inputId.vendor; + identifier.version = inputId.version; + + // Get device physical location. + if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { + //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); + } else { + buffer[sizeof(buffer) - 1] = '\0'; + identifier.location.setTo(buffer); + } + + // Get device unique id. + if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { + //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); + } else { + buffer[sizeof(buffer) - 1] = '\0'; + identifier.uniqueId.setTo(buffer); + } + + // Make file descriptor non-blocking for use with poll(). if (fcntl(fd, F_SETFL, O_NONBLOCK)) { LOGE("Error %d making device file descriptor non-blocking.", errno); close(fd); return -1; } - int devid = 0; - while (devid < mNumDevicesById) { - if (mDevicesById[devid].device == NULL) { - break; - } - devid++; - } - if (devid >= mNumDevicesById) { - device_ent* new_devids = (device_ent*)realloc(mDevicesById, - sizeof(mDevicesById[0]) * (devid + 1)); - if (new_devids == NULL) { - LOGE("out of memory"); - return -1; - } - mDevicesById = new_devids; - mNumDevicesById = devid+1; - mDevicesById[devid].device = NULL; - mDevicesById[devid].seq = 0; - } - - mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<> 16, (version >> 8) & 0xff, version & 0xff); + LOGI("add device %d: %s\n", deviceId, devicePath); + LOGI(" bus: %04x\n" + " vendor %04x\n" + " product %04x\n" + " version %04x\n", + identifier.bus, identifier.vendor, identifier.product, identifier.version); + LOGI(" name: \"%s\"\n", identifier.name.string()); + LOGI(" location: \"%s\"\n", identifier.location.string()); + LOGI(" unique id: \"%s\"\n", identifier.uniqueId.string()); + LOGI(" driver: v%d.%d.%d\n", + driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); #endif - device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name); - if (device == NULL) { - LOGE("out of memory"); - return -1; - } - - device->fd = fd; - mFDs[mFDCount].fd = fd; - mFDs[mFDCount].events = POLLIN; - mFDs[mFDCount].revents = 0; - // Load the configuration file for the device. loadConfiguration(device); @@ -798,7 +791,7 @@ int EventHub::openDevice(const char *deviceName) { bool hasSwitches = false; if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) { for (int i=0; iid, i, test_bit(i, sw_bitmask)); + //LOGI("Device %d sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask)); if (test_bit(i, sw_bitmask)) { hasSwitches = true; if (mSwitches[i] == 0) { @@ -812,37 +805,29 @@ int EventHub::openDevice(const char *deviceName) { } #endif - if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) { - // a more descriptive name - device->name = name; - - // Configure the keymap for the device. - configureKeyMap(device); - - // Tell the world about the devname (the descriptive name) - if (!mHaveFirstKeyboard && !device->keyMapInfo.isDefaultKeyMap && 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; - setKeyboardProperties(device, true); - } else { - // ensure mFirstKeyboardId is set to -something-. - if (mFirstKeyboardId == -1) { - mFirstKeyboardId = device->id; - setKeyboardProperties(device, true); - } + if ((device->classes & INPUT_DEVICE_CLASS_TOUCHSCREEN)) { + // Load the virtual keys for the touch screen, if any. + // We do this now so that we can make sure to load the keymap if necessary. + status_t status = loadVirtualKeyMap(device); + if (!status) { + device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } + } + + if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) { + // Load the keymap for the device. + status_t status = loadKeyMap(device); + + // Set system properties for the keyboard. setKeyboardProperties(device, false); - // Load the keylayout. - if (!device->keyMapInfo.keyLayoutFile.isEmpty()) { - status_t status = KeyLayoutMap::load(device->keyMapInfo.keyLayoutFile, - &device->layoutMap); - if (status) { - LOGE("Error %d loading key layout file '%s'.", status, - device->keyMapInfo.keyLayoutFile.string()); - } + // Register the keyboard as a built-in keyboard if it is eligible. + if (!status + && mBuiltInKeyboardId == -1 + && isEligibleBuiltInKeyboard(device->identifier, + device->configuration, &device->keyMap)) { + mBuiltInKeyboardId = device->id; + setKeyboardProperties(device, true); } // 'Q' key support = cheap test of whether this is an alpha-capable kbd @@ -866,76 +851,87 @@ int EventHub::openDevice(const char *deviceName) { break; } } - - LOGI("New keyboard: device->id=0x%x devname='%s' keylayout='%s' keycharactermap='%s'\n", - device->id, name, - device->keyMapInfo.keyLayoutFile.string(), - device->keyMapInfo.keyCharacterMapFile.string()); } // If the device isn't recognized as something we handle, don't monitor it. if (device->classes == 0) { - LOGV("Dropping device %s %p, id = %d\n", deviceName, device, devid); - close(fd); + LOGV("Dropping device: id=%d, path='%s', name='%s'", + deviceId, devicePath, device->identifier.name.string()); delete device; return -1; } - LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x " - "configuration='%s'\n", - deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes, - device->configurationFile.string()); + LOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " + "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s", + deviceId, fd, devicePath, device->identifier.name.string(), + device->classes, + device->configurationFile.string(), + device->keyMap.keyLayoutFile.string(), + device->keyMap.keyCharacterMapFile.string(), + toString(mBuiltInKeyboardId == deviceId)); - LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n", - deviceName, device, mFDCount, devid, device->classes); + struct pollfd pollfd; + pollfd.fd = fd; + pollfd.events = POLLIN; + pollfd.revents = 0; + mFds.push(pollfd); + mDevices.push(device); - mDevicesById[devid].device = device; device->next = mOpeningDevices; mOpeningDevices = device; - mDevices[mFDCount] = device; - - mFDCount++; return 0; } -void EventHub::loadConfiguration(device_t* device) { - device->configurationFile = getInputDeviceConfigurationFilePath(device->name, - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); +void EventHub::loadConfiguration(Device* device) { + device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier( + device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); if (device->configurationFile.isEmpty()) { - LOGI("No input device configuration file found for device '%s'.", - device->name.string()); + LOGD("No input device configuration file found for device '%s'.", + device->identifier.name.string()); } else { status_t status = PropertyMap::load(device->configurationFile, &device->configuration); if (status) { - LOGE("Error loading input device configuration file for device '%s'.", - device->name.string()); + LOGE("Error loading input device configuration file for device '%s'. " + "Using default configuration.", + device->identifier.name.string()); } } } -void EventHub::configureKeyMap(device_t* device) { - android::resolveKeyMap(device->name, device->configuration, device->keyMapInfo); +status_t EventHub::loadVirtualKeyMap(Device* device) { + // The virtual key map is supplied by the kernel as a system board property file. + String8 path; + path.append("/sys/board_properties/virtualkeys."); + path.append(device->identifier.name); + if (access(path.string(), R_OK)) { + return NAME_NOT_FOUND; + } + return VirtualKeyMap::load(path, &device->virtualKeyMap); } -void EventHub::setKeyboardProperties(device_t* device, bool firstKeyboard) { - int32_t id = firstKeyboard ? 0 : device->id; - android::setKeyboardProperties(id, device->name, device->keyMapInfo); +status_t EventHub::loadKeyMap(Device* device) { + return device->keyMap.load(device->identifier, device->configuration); } -void EventHub::clearKeyboardProperties(device_t* device, bool firstKeyboard) { - int32_t id = firstKeyboard ? 0 : device->id; +void EventHub::setKeyboardProperties(Device* device, bool builtInKeyboard) { + int32_t id = builtInKeyboard ? 0 : device->id; + android::setKeyboardProperties(id, device->identifier, + device->keyMap.keyLayoutFile, device->keyMap.keyCharacterMapFile); +} + +void EventHub::clearKeyboardProperties(Device* device, bool builtInKeyboard) { + int32_t id = builtInKeyboard ? 0 : device->id; android::clearKeyboardProperties(id); } -bool EventHub::hasKeycodeLocked(device_t* device, int keycode) const -{ - if (device->keyBitmask == NULL || device->layoutMap == NULL) { +bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { + if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { return false; } Vector scanCodes; - device->layoutMap->findScanCodes(keycode, &scanCodes); + device->keyMap.keyLayoutMap->findScanCodes(keycode, &scanCodes); const size_t N = scanCodes.size(); for (size_t i=0; ipath.string(), deviceName) == 0) { - //LOGD("remove device %d: %s\n", i, deviceName); - device_t* device = mDevices[i]; - - LOGI("Removed device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", - device->path.string(), device->name.string(), device->id, - mNumDevicesById, mFDCount, mFDs[i].fd, device->classes); - - // Clear this device's entry. - int index = (device->id&ID_MASK); - mDevicesById[index].device = NULL; - - // Close the file descriptor and compact the fd array. - close(mFDs[i].fd); - int count = mFDCount - i - 1; - memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count); - memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count); - mFDCount--; + for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) { + Device* device = mDevices[i]; + if (device->path == devicePath) { + LOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n", + device->path.string(), device->identifier.name.string(), device->id, + device->fd, device->classes); #ifdef EV_SW for (int j=0; jnext = mClosingDevices; - mClosingDevices = device; - if (device->id == mFirstKeyboardId) { + if (device->id == mBuiltInKeyboardId) { LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", - device->path.string(), mFirstKeyboardId); - mFirstKeyboardId = -1; + device->path.string(), mBuiltInKeyboardId); + mBuiltInKeyboardId = -1; clearKeyboardProperties(device, true); } clearKeyboardProperties(device, false); + + mFds.removeAt(i); + mDevices.removeAt(i); + device->close(); + + device->next = mClosingDevices; + mClosingDevices = device; return 0; } } - LOGE("remove device: %s not found\n", deviceName); + LOGE("remove device: %s not found\n", devicePath); return -1; } @@ -1016,7 +1002,7 @@ int EventHub::readNotify(int nfd) { } //printf("got %d bytes of event information\n", res); - strcpy(devname, device_path); + strcpy(devname, DEVICE_PATH); filename = devname + strlen(devname); *filename++ = '/'; @@ -1040,7 +1026,6 @@ int EventHub::readNotify(int nfd) { return 0; } - int EventHub::scanDir(const char *dirname) { char devname[PATH_MAX]; @@ -1071,28 +1056,32 @@ void EventHub::dump(String8& dump) { { // acquire lock AutoMutex _l(mLock); - dump.appendFormat(INDENT "HaveFirstKeyboard: %s\n", toString(mHaveFirstKeyboard)); - dump.appendFormat(INDENT "FirstKeyboardId: 0x%x\n", mFirstKeyboardId); + dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId); dump.append(INDENT "Devices:\n"); - for (int i = 0; i < mNumDevicesById; i++) { - const device_t* device = mDevicesById[i].device; + for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) { + const Device* device = mDevices[i]; if (device) { - if (mFirstKeyboardId == device->id) { - dump.appendFormat(INDENT2 "0x%x: %s (aka device 0 - first keyboard)\n", - device->id, device->name.string()); + if (mBuiltInKeyboardId == device->id) { + dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", + device->id, device->identifier.name.string()); } else { - dump.appendFormat(INDENT2 "0x%x: %s\n", device->id, device->name.string()); + dump.appendFormat(INDENT2 "%d: %s\n", device->id, + device->identifier.name.string()); } dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes); dump.appendFormat(INDENT3 "Path: %s\n", device->path.string()); - dump.appendFormat(INDENT3 "IsDefaultKeyMap: %s\n", - toString(device->keyMapInfo.isDefaultKeyMap)); + dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string()); + dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string()); + dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " + "product=0x%04x, version=0x%04x\n", + device->identifier.bus, device->identifier.vendor, + device->identifier.product, device->identifier.version); dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n", - device->keyMapInfo.keyLayoutFile.string()); + device->keyMap.keyLayoutFile.string()); dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n", - device->keyMapInfo.keyCharacterMapFile.string()); + device->keyMap.keyCharacterMapFile.string()); dump.appendFormat(INDENT3 "ConfigurationFile: %s\n", device->configurationFile.string()); } diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index 9e697db5c..b8d59e68e 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -11,6 +11,7 @@ #include #include +#include #include @@ -28,12 +29,16 @@ static const char* CONFIGURATION_FILE_EXTENSION[] = { ".kcm", }; +static bool isValidNameChar(char ch) { + return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_'); +} + static void appendInputDeviceConfigurationFileRelativePath(String8& path, const String8& name, InputDeviceConfigurationFileType type) { path.append(CONFIGURATION_FILE_DIR[type]); for (size_t i = 0; i < name.length(); i++) { char ch = name[i]; - if (ch == ' ') { + if (!isValidNameChar(ch)) { ch = '_'; } path.append(&ch, 1); @@ -41,7 +46,37 @@ static void appendInputDeviceConfigurationFileRelativePath(String8& path, path.append(CONFIGURATION_FILE_EXTENSION[type]); } -extern String8 getInputDeviceConfigurationFilePath( +String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( + const InputDeviceIdentifier& deviceIdentifier, + InputDeviceConfigurationFileType type) { + if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) { + if (deviceIdentifier.version != 0) { + // Try vendor product version. + String8 versionPath(getInputDeviceConfigurationFilePathByName( + String8::format("Vendor_%04x_Product_%04x_Version_%04x", + deviceIdentifier.vendor, deviceIdentifier.product, + deviceIdentifier.version), + type)); + if (!versionPath.isEmpty()) { + return versionPath; + } + } + + // Try vendor product. + String8 productPath(getInputDeviceConfigurationFilePathByName( + String8::format("Vendor_%04x_Product_%04x", + deviceIdentifier.vendor, deviceIdentifier.product), + type)); + if (!productPath.isEmpty()) { + return productPath; + } + } + + // Try device name. + return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type); +} + +String8 getInputDeviceConfigurationFilePathByName( const String8& name, InputDeviceConfigurationFileType type) { // Search system repository. String8 path; diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 07082232a..f1223f120 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -315,7 +315,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, // Throttle it! #if DEBUG_THROTTLING LOGD("Throttling - Delaying motion event for " - "device 0x%x, source 0x%08x by up to %0.3fms.", + "device %d, source 0x%08x by up to %0.3fms.", deviceId, source, (nextTime - currentTime) * 0.000001); #endif if (nextTime < *nextWakeupTime) { @@ -704,7 +704,7 @@ bool InputDispatcher::dispatchKeyLocked( void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("%seventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, " + LOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, " "repeatCount=%d, downTime=%lld", prefix, @@ -767,7 +767,7 @@ bool InputDispatcher::dispatchMotionLocked( void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("%seventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, " + LOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, " "metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", prefix, @@ -2072,7 +2072,7 @@ void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t sou uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) { #if DEBUG_INBOUND_EVENT_DETAILS - LOGD("notifyKey - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, action=0x%x, " + LOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, " "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld", eventTime, deviceId, source, policyFlags, action, flags, keyCode, scanCode, metaState, downTime); @@ -2120,7 +2120,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime) { #if DEBUG_INBOUND_EVENT_DETAILS - LOGD("notifyMotion - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, " + LOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, metaState=0x%x, edgeFlags=0x%x, " "xPrecision=%f, yPrecision=%f, downTime=%lld", eventTime, deviceId, source, policyFlags, action, flags, metaState, edgeFlags, diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index aa690e5fd..9cc96adf3 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -121,7 +122,7 @@ void InputReader::loopOnce() { mEventHub->getEvent(& rawEvent); #if DEBUG_RAW_EVENTS - LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d", + LOGD("Input event: device=%d type=0x%x scancode=%d keycode=%d value=%d", rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode, rawEvent.value); #endif @@ -157,9 +158,9 @@ void InputReader::addDevice(int32_t deviceId) { device->configure(); if (device->isIgnored()) { - LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", deviceId, name.string()); + LOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, name.string()); } else { - LOGI("Device added: id=0x%x, name=%s, sources=%08x", deviceId, name.string(), + LOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, name.string(), device->getSources()); } @@ -201,10 +202,10 @@ void InputReader::removeDevice(int32_t deviceId) { } if (device->isIgnored()) { - LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)", + LOGI("Device removed: id=%d, name='%s' (ignored non-input device)", device->getId(), device->getName().string()); } else { - LOGI("Device removed: id=0x%x, name=%s, sources=%08x", + LOGI("Device removed: id=%d, name='%s', sources=0x%08x", device->getId(), device->getName().string(), device->getSources()); } @@ -535,7 +536,7 @@ void InputDevice::dump(String8& dump) { InputDeviceInfo deviceInfo; getDeviceInfo(& deviceInfo); - dump.appendFormat(INDENT "Device 0x%x: %s\n", deviceInfo.getId(), + dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(), deviceInfo.getName().string()); dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); @@ -1439,7 +1440,7 @@ bool TouchInputMapper::configureSurfaceLocked() { bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height; if (sizeChanged) { - LOGI("Device reconfigured: id=0x%x, name=%s, display size is now %dx%d", + LOGI("Device reconfigured: id=%d, name='%s', display size is now %dx%d", getDeviceId(), getDeviceName().string(), width, height); mLocked.surfaceWidth = width; @@ -1651,9 +1652,8 @@ void TouchInputMapper::dumpSurfaceLocked(String8& dump) { void TouchInputMapper::configureVirtualKeysLocked() { assert(mRawAxes.x.valid && mRawAxes.y.valid); - // Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock. Vector virtualKeyDefinitions; - getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions); + getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); mLocked.virtualKeys.clear(); diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp index a4cc22d45..6faa600e6 100644 --- a/libs/ui/Keyboard.cpp +++ b/libs/ui/Keyboard.cpp @@ -22,97 +22,167 @@ #include #include +#include +#include #include #include #include namespace android { -static bool probeKeyMap(KeyMapInfo& keyMapInfo, const String8& keyMapName, bool defaultKeyMap) { - bool foundOne = false; - if (keyMapInfo.keyLayoutFile.isEmpty()) { - keyMapInfo.keyLayoutFile.setTo(getInputDeviceConfigurationFilePath(keyMapName, - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT)); - if (!keyMapInfo.keyLayoutFile.isEmpty()) { - foundOne = true; - } - } +// --- KeyMap --- - if (keyMapInfo.keyCharacterMapFile.isEmpty()) { - keyMapInfo.keyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath(keyMapName, - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP)); - if (!keyMapInfo.keyCharacterMapFile.isEmpty()) { - foundOne = true; - } - } - - if (foundOne && defaultKeyMap) { - keyMapInfo.isDefaultKeyMap = true; - } - return keyMapInfo.isComplete(); +KeyMap::KeyMap() : + keyLayoutMap(NULL), keyCharacterMap(NULL) { } -status_t resolveKeyMap(const String8& deviceName, - const PropertyMap* deviceConfiguration, KeyMapInfo& outKeyMapInfo) { +KeyMap::~KeyMap() { + delete keyLayoutMap; + delete keyCharacterMap; +} + +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)) { - outKeyMapInfo.keyLayoutFile.setTo(getInputDeviceConfigurationFilePath( - keyLayoutName, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT)); - if (outKeyMapInfo.keyLayoutFile.isEmpty()) { - LOGW("Configuration for keyboard device '%s' requested keyboard layout '%s' but " + 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.", - deviceName.string(), keyLayoutName.string()); + deviceIdenfifier.name.string(), keyLayoutName.string()); } } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), keyCharacterMapName)) { - outKeyMapInfo.keyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath( - keyCharacterMapName, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP)); - if (outKeyMapInfo.keyCharacterMapFile.isEmpty()) { - LOGW("Configuration for keyboard device '%s' requested keyboard character " + 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.", - deviceName.string(), keyCharacterMapName.string()); + deviceIdenfifier.name.string(), keyLayoutName.string()); } } - if (outKeyMapInfo.isComplete()) { + if (isComplete()) { return OK; } } - // Try searching by device name. - if (probeKeyMap(outKeyMapInfo, deviceName, false)) { + // 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.). - if (probeKeyMap(outKeyMapInfo, String8("Generic"), true)) { + // 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; } // Give up! - LOGE("Could not determine key map for device '%s' and the Generic key map was not found!", - deviceName.string()); - outKeyMapInfo.isDefaultKeyMap = true; + LOGE("Could not determine key map for device '%s' and no default key maps were found!", + deviceIdenfifier.name.string()); return NAME_NOT_FOUND; } -void setKeyboardProperties(int32_t deviceId, const String8& deviceName, - const KeyMapInfo& keyMapInfo) { +bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, + const String8& keyMapName) { + if (!haveKeyLayout()) { + loadKeyLayout(deviceIdentifier, keyMapName); + } + if (!haveKeyCharacterMap()) { + loadKeyCharacterMap(deviceIdentifier, keyMapName); + } + return isComplete(); +} + +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; + } + + KeyLayoutMap* map; + status_t status = KeyLayoutMap::load(path, &map); + if (status) { + return status; + } + + keyLayoutFile.setTo(path); + keyLayoutMap = map; + return OK; +} + +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; +} + +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()); + 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) { @@ -126,29 +196,24 @@ void clearKeyboardProperties(int32_t deviceId) { } status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFile) { - if (deviceId == DEVICE_ID_VIRTUAL_KEYBOARD) { - outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath(String8("Virtual"), - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP)); - if (!outKeyCharacterMapFile.isEmpty()) { + 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; } } - 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; - } - - outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath(String8("Generic"), + // 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 Virtual and Generic key maps)"); + LOGE("Can't find any key character map files including the Virtual key map!"); return NAME_NOT_FOUND; } diff --git a/libs/ui/VirtualKeyMap.cpp b/libs/ui/VirtualKeyMap.cpp new file mode 100644 index 000000000..e756cdd78 --- /dev/null +++ b/libs/ui/VirtualKeyMap.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "VirtualKeyMap" + +#include +#include +#include +#include +#include +#include +#include + +// Enables debug output for the parser. +#define DEBUG_PARSER 0 + +// Enables debug output for parser performance. +#define DEBUG_PARSER_PERFORMANCE 0 + + +namespace android { + +static const char* WHITESPACE = " \t\r"; +static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:"; + + +// --- VirtualKeyMap --- + +VirtualKeyMap::VirtualKeyMap() { +} + +VirtualKeyMap::~VirtualKeyMap() { +} + +status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) { + *outMap = NULL; + + Tokenizer* tokenizer; + status_t status = Tokenizer::open(filename, &tokenizer); + if (status) { + LOGE("Error %d opening virtual key map file %s.", status, filename.string()); + } else { + VirtualKeyMap* map = new VirtualKeyMap(); + if (!map) { + LOGE("Error allocating virtual key map."); + status = NO_MEMORY; + } else { +#if DEBUG_PARSER_PERFORMANCE + nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); +#endif + Parser parser(map, tokenizer); + status = parser.parse(); +#if DEBUG_PARSER_PERFORMANCE + nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; + LOGD("Parsed key character map file '%s' %d lines in %0.3fms.", + tokenizer->getFilename().string(), tokenizer->getLineNumber(), + elapsedTime / 1000000.0); +#endif + if (status) { + delete map; + } else { + *outMap = map; + } + } + delete tokenizer; + } + return status; +} + + +// --- VirtualKeyMap::Parser --- + +VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) : + mMap(map), mTokenizer(tokenizer) { +} + +VirtualKeyMap::Parser::~Parser() { +} + +status_t VirtualKeyMap::Parser::parse() { + while (!mTokenizer->isEof()) { +#if DEBUG_PARSER + LOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), + mTokenizer->peekRemainderOfLine().string()); +#endif + + mTokenizer->skipDelimiters(WHITESPACE); + + if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { + // Multiple keys can appear on one line or they can be broken up across multiple lines. + do { + String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); + if (token != "0x01") { + LOGE("%s: Unknown virtual key type, expected 0x01.", + mTokenizer->getLocation().string()); + return BAD_VALUE; + } + + VirtualKeyDefinition defn; + bool success = parseNextIntField(&defn.scanCode) + && parseNextIntField(&defn.centerX) + && parseNextIntField(&defn.centerY) + && parseNextIntField(&defn.width) + && parseNextIntField(&defn.height); + if (!success) { + LOGE("%s: Expected 5 colon-delimited integers in virtual key definition.", + mTokenizer->getLocation().string()); + return BAD_VALUE; + } + +#if DEBUG_PARSER + LOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, " + "width=%d, height=%d", + defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height); +#endif + mMap->mVirtualKeys.push(defn); + } while (consumeFieldDelimiterAndSkipWhitespace()); + + if (!mTokenizer->isEol()) { + LOGE("%s: Expected end of line, got '%s'.", + mTokenizer->getLocation().string(), + mTokenizer->peekRemainderOfLine().string()); + return BAD_VALUE; + } + } + + mTokenizer->nextLine(); + } + + return NO_ERROR; +} + +bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() { + mTokenizer->skipDelimiters(WHITESPACE); + if (mTokenizer->peekChar() == ':') { + mTokenizer->nextChar(); + mTokenizer->skipDelimiters(WHITESPACE); + return true; + } + return false; +} + +bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) { + if (!consumeFieldDelimiterAndSkipWhitespace()) { + return false; + } + + String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); + char* end; + *outValue = strtol(token.string(), &end, 0); + if (token.isEmpty() || *end != '\0') { + LOGE("Expected an integer, got '%s'.", token.string()); + return false; + } + return true; +} + +} // namespace android diff --git a/libs/ui/tests/InputReader_test.cpp b/libs/ui/tests/InputReader_test.cpp index 05bebc5e3..d6c2cbd8c 100644 --- a/libs/ui/tests/InputReader_test.cpp +++ b/libs/ui/tests/InputReader_test.cpp @@ -42,7 +42,6 @@ class FakeInputReaderPolicy : public InputReaderPolicyInterface { KeyedVector mDisplayInfos; bool mFilterTouchEvents; bool mFilterJumpyTouchEvents; - KeyedVector > mVirtualKeyDefinitions; Vector mExcludedDeviceNames; protected: @@ -75,15 +74,6 @@ public: mFilterJumpyTouchEvents = enabled; } - void addVirtualKeyDefinition(const String8& deviceName, - const VirtualKeyDefinition& definition) { - if (mVirtualKeyDefinitions.indexOfKey(deviceName) < 0) { - mVirtualKeyDefinitions.add(deviceName, Vector()); - } - - mVirtualKeyDefinitions.editValueFor(deviceName).push(definition); - } - void addExcludedDeviceName(const String8& deviceName) { mExcludedDeviceNames.push(deviceName); } @@ -116,14 +106,6 @@ private: return mFilterJumpyTouchEvents; } - virtual void getVirtualKeyDefinitions(const String8& deviceName, - Vector& outVirtualKeyDefinitions) { - ssize_t index = mVirtualKeyDefinitions.indexOfKey(deviceName); - if (index >= 0) { - outVirtualKeyDefinitions.appendVector(mVirtualKeyDefinitions.valueAt(index)); - } - } - virtual void getExcludedDeviceNames(Vector& outExcludedDeviceNames) { outExcludedDeviceNames.appendVector(mExcludedDeviceNames); } @@ -355,6 +337,7 @@ class FakeEventHub : public EventHubInterface { KeyedVector switchStates; KeyedVector keys; KeyedVector leds; + Vector virtualKeys; Device(const String8& name, uint32_t classes) : name(name), classes(classes) { @@ -448,6 +431,11 @@ public: return mExcludedDevices; } + void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) { + Device* device = getDevice(deviceId); + device->virtualKeys.push(definition); + } + void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type, int32_t scanCode, int32_t keyCode, int32_t value, uint32_t flags) { RawEvent event; @@ -603,6 +591,16 @@ private: } } + virtual void getVirtualKeyDefinitions(int32_t deviceId, + Vector& outVirtualKeys) const { + outVirtualKeys.clear(); + + Device* device = getDevice(deviceId); + if (device) { + outVirtualKeys.appendVector(device->virtualKeys); + } + } + virtual void dump(String8& dump) { } }; @@ -2147,8 +2145,8 @@ void TouchInputMapperTest::prepareDisplay(int32_t orientation) { } void TouchInputMapperTest::prepareVirtualKeys() { - mFakePolicy->addVirtualKeyDefinition(String8(DEVICE_NAME), VIRTUAL_KEYS[0]); - mFakePolicy->addVirtualKeyDefinition(String8(DEVICE_NAME), VIRTUAL_KEYS[1]); + mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]); + mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]); mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, AKEYCODE_HOME, POLICY_FLAG_WAKE); mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, AKEYCODE_MENU, POLICY_FLAG_WAKE); } diff --git a/libs/utils/FileMap.cpp b/libs/utils/FileMap.cpp index e1ba9b238..f1f8bdadf 100644 --- a/libs/utils/FileMap.cpp +++ b/libs/utils/FileMap.cpp @@ -63,16 +63,18 @@ FileMap::~FileMap(void) free(mFileName); } #ifdef HAVE_POSIX_FILEMAP - if (munmap(mBasePtr, mBaseLength) != 0) { + if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) { LOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength); } #endif #ifdef HAVE_WIN32_FILEMAP - if ( UnmapViewOfFile(mBasePtr) == 0) { + if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) { LOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr, GetLastError() ); } - CloseHandle(mFileMapping); + if (mFileMapping != INVALID_HANDLE_VALUE) { + CloseHandle(mFileMapping); + } CloseHandle(mFileHandle); #endif } diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp index e531a2a0f..0bc5aff22 100644 --- a/libs/utils/String8.cpp +++ b/libs/utils/String8.cpp @@ -195,6 +195,24 @@ String8::~String8() SharedBuffer::bufferFromData(mString)->release(); } +String8 String8::format(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + + String8 result(formatV(fmt, args)); + + va_end(args); + return result; +} + +String8 String8::formatV(const char* fmt, va_list args) +{ + String8 result; + result.appendFormatV(fmt, args); + return result; +} + void String8::clear() { SharedBuffer::bufferFromData(mString)->release(); mString = getEmptyString(); diff --git a/libs/utils/Tokenizer.cpp b/libs/utils/Tokenizer.cpp index 9251973ca..b3445b797 100644 --- a/libs/utils/Tokenizer.cpp +++ b/libs/utils/Tokenizer.cpp @@ -35,16 +35,16 @@ static inline bool isDelimiter(char ch, const char* delimiters) { return strchr(delimiters, ch) != NULL; } - -Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, - const char* buffer, size_t length) : - mFilename(filename), mFileMap(fileMap), mBuffer(buffer), mLength(length), - mCurrent(buffer), mLineNumber(1) { +Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length) : + mFilename(filename), mFileMap(fileMap), + mBuffer(buffer), mLength(length), mCurrent(buffer), mLineNumber(1) { } Tokenizer::~Tokenizer() { if (mFileMap) { mFileMap->release(); + } else { + delete[] mBuffer; } } @@ -63,22 +63,33 @@ status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { LOGE("Error getting size of file '%s', %s.", filename.string(), strerror(errno)); } else { size_t length = size_t(stat.st_size); - FileMap* fileMap = new FileMap(); - if (!fileMap->create(NULL, fd, 0, length, true)) { - result = NO_MEMORY; - LOGE("Error mapping file '%s', %s.", filename.string(), strerror(errno)); - } else { - fileMap->advise(FileMap::SEQUENTIAL); - *outTokenizer = new Tokenizer(filename, fileMap, - static_cast(fileMap->getDataPtr()), length); - if (!*outTokenizer) { - result = NO_MEMORY; - LOGE("Error allocating tokenizer for file=%s.", filename.string()); + FileMap* fileMap = new FileMap(); + char* buffer; + if (fileMap->create(NULL, fd, 0, length, true)) { + fileMap->advise(FileMap::SEQUENTIAL); + buffer = static_cast(fileMap->getDataPtr()); + } else { + fileMap->release(); + fileMap = NULL; + + // Fall back to reading into a buffer since we can't mmap files in sysfs. + // The length we obtained from stat is wrong too (it will always be 4096) + // so we must trust that read will read the entire file. + buffer = new char[length]; + ssize_t nrd = read(fd, buffer, length); + if (nrd < 0) { + result = -errno; + LOGE("Error reading file '%s', %s.", filename.string(), strerror(errno)); + delete[] buffer; + buffer = NULL; + } else { + length = size_t(nrd); } } - if (result) { - fileMap->release(); + + if (!result) { + *outTokenizer = new Tokenizer(filename, fileMap, buffer, length); } } close(fd);