diff options
30 files changed, 1021 insertions, 750 deletions
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 5f3184d..dcde6ef 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -2611,6 +2611,10 @@ public final class ViewRoot extends Handler implements ViewParent, captureKeyLog("captureDispatchKeyEvent", event); } + // Make sure the fallback event policy sees all keys that will be delivered to the + // view hierarchy. + mFallbackEventHandler.preDispatchKeyEvent(event); + // Deliver the key to the view hierarchy. if (mView.dispatchKeyEvent(event)) { finishKeyEvent(event, sendDone, true); diff --git a/data/keyboards/Logitech_USB_Receiver.kl b/data/keyboards/Vendor_046d_Product_c532.kl index aa7c0ee..741c2e1 100644 --- a/data/keyboards/Logitech_USB_Receiver.kl +++ b/data/keyboards/Vendor_046d_Product_c532.kl @@ -13,7 +13,7 @@ # limitations under the License. # -# Logitech Revue keyboard +# Logitech Revue Wireless keyboard # # Notes: # - The GRAVE key is emulated by the keyboard. diff --git a/data/keyboards/Apple_Wireless_Keyboard.kl b/data/keyboards/Vendor_05ac_Product_0239.kl index 5234d58..5234d58 100644 --- a/data/keyboards/Apple_Wireless_Keyboard.kl +++ b/data/keyboards/Vendor_05ac_Product_0239.kl diff --git a/data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kl b/data/keyboards/Vendor_22b8_Product_093d.kl index 87b3c32..87b3c32 100644 --- a/data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kl +++ b/data/keyboards/Vendor_22b8_Product_093d.kl diff --git a/data/keyboards/common.mk b/data/keyboards/common.mk index 5c2a75d..56c287a 100644 --- a/data/keyboards/common.mk +++ b/data/keyboards/common.mk @@ -16,16 +16,20 @@ # Used by Android.mk and keyboards.mk. keylayouts := \ - Apple_Wireless_Keyboard.kl \ - AVRCP.kl \ Generic.kl \ - Logitech_USB_Receiver.kl \ - Motorola_Bluetooth_Wireless_Keyboard.kl \ + AVRCP.kl \ qwerty.kl \ - qwerty2.kl + Vendor_046d_Product_c532.kl \ + Vendor_05ac_Product_0239.kl \ + Vendor_22b8_Product_093d.kl keycharmaps := \ Generic.kcm \ + Virtual.kcm \ qwerty.kcm \ - qwerty2.kcm \ - Virtual.kcm + qwerty2.kcm + +keyconfigs := \ + qwerty.idc \ + qwerty2.idc + diff --git a/data/keyboards/keyboards.mk b/data/keyboards/keyboards.mk index b32e436..564f41c 100644 --- a/data/keyboards/keyboards.mk +++ b/data/keyboards/keyboards.mk @@ -22,4 +22,8 @@ PRODUCT_COPY_FILES := $(foreach file,$(keylayouts),\ PRODUCT_COPY_FILES += $(foreach file,$(keycharmaps),\ frameworks/base/data/keyboards/$(file):system/usr/keychars/$(file)) -PRODUCT_PACKAGES := $(keylayouts) $(keycharmaps) +PRODUCT_COPY_FILES += $(foreach file,$(keyconfigs),\ + frameworks/base/data/keyboards/$(file):system/usr/idc/$(file)) + +PRODUCT_PACKAGES := $(keylayouts) $(keycharmaps) $(keyconfigs) + diff --git a/data/keyboards/qwerty.idc b/data/keyboards/qwerty.idc new file mode 100644 index 0000000..129b0bc --- /dev/null +++ b/data/keyboards/qwerty.idc @@ -0,0 +1,23 @@ +# 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. + +# +# Emulator keyboard configuration file #1. +# + +keyboard.layout = qwerty +keyboard.characterMap = qwerty +keyboard.orientationAware = 1 +keyboard.builtIn = 1 + diff --git a/data/keyboards/qwerty2.idc b/data/keyboards/qwerty2.idc new file mode 100644 index 0000000..1a795c6 --- /dev/null +++ b/data/keyboards/qwerty2.idc @@ -0,0 +1,23 @@ +# 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. + +# +# Emulator keyboard configuration file #2. +# + +keyboard.layout = qwerty +keyboard.characterMap = qwerty2 +keyboard.orientationAware = 1 +keyboard.builtIn = 1 + diff --git a/data/keyboards/qwerty2.kl b/data/keyboards/qwerty2.kl deleted file mode 100644 index 863a258..0000000 --- a/data/keyboards/qwerty2.kl +++ /dev/null @@ -1,109 +0,0 @@ -# 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. - -# -# Emulator keyboard layout #2. -# - -key 399 GRAVE -key 2 1 -key 3 2 -key 4 3 -key 5 4 -key 6 5 -key 7 6 -key 8 7 -key 9 8 -key 10 9 -key 11 0 -key 158 BACK WAKE_DROPPED -key 230 SOFT_RIGHT WAKE -key 60 SOFT_RIGHT WAKE -key 107 ENDCALL WAKE_DROPPED -key 62 ENDCALL WAKE_DROPPED -key 229 MENU WAKE_DROPPED -key 139 MENU WAKE_DROPPED -key 59 MENU WAKE_DROPPED -key 127 SEARCH WAKE_DROPPED -key 217 SEARCH WAKE_DROPPED -key 228 POUND -key 227 STAR -key 231 CALL WAKE_DROPPED -key 61 CALL WAKE_DROPPED -key 232 DPAD_CENTER WAKE_DROPPED -key 108 DPAD_DOWN WAKE_DROPPED -key 103 DPAD_UP WAKE_DROPPED -key 102 HOME WAKE -key 105 DPAD_LEFT WAKE_DROPPED -key 106 DPAD_RIGHT WAKE_DROPPED -key 115 VOLUME_UP WAKE -key 114 VOLUME_DOWN WAKE -key 116 POWER WAKE -key 212 CAMERA - -key 16 Q -key 17 W -key 18 E -key 19 R -key 20 T -key 21 Y -key 22 U -key 23 I -key 24 O -key 25 P -key 26 LEFT_BRACKET -key 27 RIGHT_BRACKET -key 43 BACKSLASH - -key 30 A -key 31 S -key 32 D -key 33 F -key 34 G -key 35 H -key 36 J -key 37 K -key 38 L -key 39 SEMICOLON -key 40 APOSTROPHE -key 14 DEL - -key 44 Z -key 45 X -key 46 C -key 47 V -key 48 B -key 49 N -key 50 M -key 51 COMMA -key 52 PERIOD -key 53 SLASH -key 28 ENTER - -key 56 ALT_LEFT -key 100 ALT_RIGHT -key 42 SHIFT_LEFT -key 54 SHIFT_RIGHT -key 15 TAB -key 57 SPACE -key 150 EXPLORER -key 155 ENVELOPE - -key 12 MINUS -key 13 EQUALS -key 215 AT - -# On an AT keyboard: ESC, F10 -key 1 BACK WAKE_DROPPED -key 68 MENU WAKE_DROPPED diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index 6c798a6..6c6c297 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 <android/input.h> +#include <ui/Input.h> #include <ui/Keyboard.h> +#include <ui/KeyLayoutMap.h> +#include <ui/KeyCharacterMap.h> +#include <ui/VirtualKeyMap.h> #include <utils/String8.h> #include <utils/threads.h> #include <utils/Log.h> @@ -27,6 +30,7 @@ #include <utils/List.h> #include <utils/Errors.h> #include <utils/PropertyMap.h> +#include <utils/Vector.h> #include <linux/input.h> @@ -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<VirtualKeyDefinition>& 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<VirtualKeyDefinition>& 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; + + // 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<struct pollfd> mFds; + Vector<Device*> mDevices; + + Device *mOpeningDevices; + Device *mClosingDevices; - bool mOpened; - bool mNeedToSendFinishedDeviceScan; - List<String8> mExcludedDevices; + bool mOpened; + bool mNeedToSendFinishedDeviceScan; + List<String8> 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 4dc8f2a..27f65bc 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -497,6 +497,23 @@ private: KeyedVector<int32_t, MotionRange> 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 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 getInputDeviceConfigurationFilePath( +extern String8 getInputDeviceConfigurationFilePathByName( const String8& name, InputDeviceConfigurationFileType type); } // namespace android diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h index cfceaab..8ec5421 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<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0; - /* Gets the excluded device names for the platform. */ virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0; }; diff --git a/include/ui/Keyboard.h b/include/ui/Keyboard.h index 689607d..50296e2 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; + + KeyMap(); + ~KeyMap(); - KeyMapInfo() : isDefaultKeyMap(false) { + status_t load(const InputDeviceIdentifier& deviceIdenfier, + const PropertyMap* deviceConfiguration); + + inline bool haveKeyLayout() const { + return !keyLayoutFile.isEmpty(); + } + + inline bool haveKeyCharacterMap() const { + return !keyCharacterMapFile.isEmpty(); } - bool isComplete() { - return !keyLayoutFile.isEmpty() && !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 0000000..7813d9d --- /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 <stdint.h> + +#include <ui/Input.h> +#include <utils/Errors.h> +#include <utils/KeyedVector.h> +#include <utils/Tokenizer.h> +#include <utils/String8.h> +#include <utils/Unicode.h> + +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<VirtualKeyDefinition>& 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<VirtualKeyDefinition> mVirtualKeys; + + VirtualKeyMap(); +}; + +} // namespace android + +#endif // _UI_KEY_CHARACTER_MAP_H diff --git a/include/utils/String8.h b/include/utils/String8.h index 6abfb06..6b49ff5 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 21e58e6..c7db5fb 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 5948e04..d0e041a 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 b312cda..8f4bac6 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -33,6 +33,8 @@ #include <assert.h> #include <ui/KeyLayoutMap.h> +#include <ui/KeyCharacterMap.h> +#include <ui/VirtualKeyMap.h> #include <string.h> #include <stdint.h> @@ -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<int32_t> 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<VirtualKeyDefinition>& 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<String8>::iterator iter = mExcludedDevices.begin(); List<String8>::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'; - } - - if (fcntl(fd, F_SETFL, O_NONBLOCK)) { - LOGE("Error %d making device file descriptor non-blocking.", errno); + // 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; } - int devid = 0; - while (devid < mNumDevicesById) { - if (mDevicesById[devid].device == NULL) { - break; - } - devid++; + // 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; } - 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; + 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); } - mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK; - if (mDevicesById[devid].seq == 0) { - mDevicesById[devid].seq = 1<<SEQ_SHIFT; + // 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); } - new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1)); - new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1)); - if (new_mFDs == NULL || new_devices == NULL) { - LOGE("out of memory"); + // 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; } - mFDs = new_mFDs; - mDevices = new_devices; + + // Allocate device. (The device object takes ownership of the fd at this point.) + int32_t deviceId = mNextDeviceId++; + Device* device = new Device(fd, deviceId, String8(devicePath), identifier); #if 0 - LOGI("add device %d: %s\n", mFDCount, deviceName); - LOGI(" bus: %04x\n" - " vendor %04x\n" - " product %04x\n" - " version %04x\n", - id.bustype, id.vendor, id.product, id.version); - LOGI(" name: \"%s\"\n", name); - LOGI(" location: \"%s\"\n" - " id: \"%s\"\n", location, idstr); - LOGI(" version: %d.%d.%d\n", - version >> 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; i<EV_SW; i++) { - //LOGI("Device 0x%x sw %d: has=%d", device->id, 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()); - - LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n", - deviceName, device, mFDCount, devid, device->classes); + 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)); + + 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<int32_t> scanCodes; - device->layoutMap->findScanCodes(keycode, &scanCodes); + device->keyMap.keyLayoutMap->findScanCodes(keycode, &scanCodes); const size_t N = scanCodes.size(); for (size_t i=0; i<N && i<=KEY_MAX; i++) { int32_t sc = scanCodes.itemAt(i); @@ -947,29 +943,15 @@ bool EventHub::hasKeycodeLocked(device_t* device, int keycode) const return false; } -int EventHub::closeDevice(const char *deviceName) { +int EventHub::closeDevice(const char *devicePath) { AutoMutex _l(mLock); - int i; - for(i = 1; i < mFDCount; i++) { - if(strcmp(mDevices[i]->path.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; j<EV_SW; j++) { @@ -978,21 +960,25 @@ int EventHub::closeDevice(const char *deviceName) { } } #endif - - device->next = 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 9e697db..b8d59e6 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -11,6 +11,7 @@ #include <stdlib.h> #include <unistd.h> +#include <ctype.h> #include <ui/Input.h> @@ -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 0708223..f1223f1 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 aa690e5..9cc96ad 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -25,6 +25,7 @@ #include <cutils/log.h> #include <ui/InputReader.h> #include <ui/Keyboard.h> +#include <ui/VirtualKeyMap.h> #include <stddef.h> #include <stdlib.h> @@ -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<VirtualKeyDefinition> 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 a4cc22d..6faa600 100644 --- a/libs/ui/Keyboard.cpp +++ b/libs/ui/Keyboard.cpp @@ -22,97 +22,167 @@ #include <ui/Keyboard.h> #include <ui/KeycodeLabels.h> +#include <ui/KeyLayoutMap.h> +#include <ui/KeyCharacterMap.h> #include <utils/Errors.h> #include <utils/Log.h> #include <cutils/properties.h> namespace android { -static 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; - } - } +KeyMap::KeyMap() : + keyLayoutMap(NULL), keyCharacterMap(NULL) { +} - if (foundOne && defaultKeyMap) { - keyMapInfo.isDefaultKeyMap = true; - } - return keyMapInfo.isComplete(); +KeyMap::~KeyMap() { + delete keyLayoutMap; + delete keyCharacterMap; } -status_t resolveKeyMap(const String8& deviceName, - const PropertyMap* deviceConfiguration, KeyMapInfo& outKeyMapInfo) { +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 0000000..e756cdd --- /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 <stdlib.h> +#include <string.h> +#include <ui/VirtualKeyMap.h> +#include <utils/Log.h> +#include <utils/Errors.h> +#include <utils/Tokenizer.h> +#include <utils/Timers.h> + +// 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 05bebc5..d6c2cbd 100644 --- a/libs/ui/tests/InputReader_test.cpp +++ b/libs/ui/tests/InputReader_test.cpp @@ -42,7 +42,6 @@ class FakeInputReaderPolicy : public InputReaderPolicyInterface { KeyedVector<int32_t, DisplayInfo> mDisplayInfos; bool mFilterTouchEvents; bool mFilterJumpyTouchEvents; - KeyedVector<String8, Vector<VirtualKeyDefinition> > mVirtualKeyDefinitions; Vector<String8> 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<VirtualKeyDefinition>()); - } - - 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<VirtualKeyDefinition>& outVirtualKeyDefinitions) { - ssize_t index = mVirtualKeyDefinitions.indexOfKey(deviceName); - if (index >= 0) { - outVirtualKeyDefinitions.appendVector(mVirtualKeyDefinitions.valueAt(index)); - } - } - virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { outExcludedDeviceNames.appendVector(mExcludedDeviceNames); } @@ -355,6 +337,7 @@ class FakeEventHub : public EventHubInterface { KeyedVector<int32_t, int32_t> switchStates; KeyedVector<int32_t, KeyInfo> keys; KeyedVector<int32_t, bool> leds; + Vector<VirtualKeyDefinition> 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<VirtualKeyDefinition>& 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 e1ba9b2..f1f8bda 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 e531a2a..0bc5aff 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 9251973..b3445b7 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 { + char* buffer; + if (fileMap->create(NULL, fd, 0, length, true)) { fileMap->advise(FileMap::SEQUENTIAL); - - *outTokenizer = new Tokenizer(filename, fileMap, - static_cast<const char*>(fileMap->getDataPtr()), length); - if (!*outTokenizer) { - result = NO_MEMORY; - LOGE("Error allocating tokenizer for file=%s.", filename.string()); + buffer = static_cast<char*>(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); diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index 9078811..8634eec 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -358,16 +358,6 @@ public class InputManager { } } - private static final class VirtualKeyDefinition { - public int scanCode; - - // configured position data, specified in display coords - public int centerX; - public int centerY; - public int width; - public int height; - } - /* * Callbacks from native. */ @@ -438,54 +428,6 @@ public class InputManager { } @SuppressWarnings("unused") - public VirtualKeyDefinition[] getVirtualKeyDefinitions(String deviceName) { - ArrayList<VirtualKeyDefinition> keys = new ArrayList<VirtualKeyDefinition>(); - - try { - FileInputStream fis = new FileInputStream( - "/sys/board_properties/virtualkeys." + deviceName); - InputStreamReader isr = new InputStreamReader(fis); - BufferedReader br = new BufferedReader(isr, 2048); - String str = br.readLine(); - if (str != null) { - String[] it = str.split(":"); - if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it); - final int N = it.length-6; - for (int i=0; i<=N; i+=6) { - if (!"0x01".equals(it[i])) { - Slog.w(TAG, "Unknown virtual key type at elem #" - + i + ": " + it[i] + " for device " + deviceName); - continue; - } - try { - VirtualKeyDefinition key = new VirtualKeyDefinition(); - key.scanCode = Integer.parseInt(it[i+1]); - key.centerX = Integer.parseInt(it[i+2]); - key.centerY = Integer.parseInt(it[i+3]); - key.width = Integer.parseInt(it[i+4]); - key.height = Integer.parseInt(it[i+5]); - if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key " - + key.scanCode + ": center=" + key.centerX + "," - + key.centerY + " size=" + key.width + "x" - + key.height); - keys.add(key); - } catch (NumberFormatException e) { - Slog.w(TAG, "Bad number in virtual key definition at region " - + i + " in: " + str + " for device " + deviceName, e); - } - } - } - br.close(); - } catch (FileNotFoundException e) { - Slog.i(TAG, "No virtual keys found for device " + deviceName + "."); - } catch (IOException e) { - Slog.w(TAG, "Error reading virtual keys for device " + deviceName + ".", e); - } - - return keys.toArray(new VirtualKeyDefinition[keys.size()]); - } - - @SuppressWarnings("unused") public String[] getExcludedDeviceNames() { ArrayList<String> names = new ArrayList<String>(); diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index aa84db5..1996dd0 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -56,7 +56,6 @@ static struct { jmethodID checkInjectEventsPermission; jmethodID filterTouchEvents; jmethodID filterJumpyTouchEvents; - jmethodID getVirtualKeyDefinitions; jmethodID getExcludedDeviceNames; jmethodID getMaxEventsPerSecond; } gCallbacksClassInfo; @@ -64,16 +63,6 @@ static struct { static struct { jclass clazz; - jfieldID scanCode; - jfieldID centerX; - jfieldID centerY; - jfieldID width; - jfieldID height; -} gVirtualKeyDefinitionClassInfo; - -static struct { - jclass clazz; - jfieldID inputChannel; jfieldID name; jfieldID layoutParamsFlags; @@ -176,8 +165,6 @@ public: int32_t* width, int32_t* height, int32_t* orientation); virtual bool filterTouchEvents(); virtual bool filterJumpyTouchEvents(); - virtual void getVirtualKeyDefinitions(const String8& deviceName, - Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions); virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames); /* --- InputDispatcherPolicyInterface implementation --- */ @@ -442,41 +429,6 @@ bool NativeInputManager::filterJumpyTouchEvents() { return mFilterJumpyTouchEvents; } -void NativeInputManager::getVirtualKeyDefinitions(const String8& deviceName, - Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) { - outVirtualKeyDefinitions.clear(); - - JNIEnv* env = jniEnv(); - - jstring deviceNameStr = env->NewStringUTF(deviceName.string()); - if (! checkAndClearExceptionFromCallback(env, "getVirtualKeyDefinitions")) { - jobjectArray result = jobjectArray(env->CallObjectMethod(mCallbacksObj, - gCallbacksClassInfo.getVirtualKeyDefinitions, deviceNameStr)); - if (! checkAndClearExceptionFromCallback(env, "getVirtualKeyDefinitions") && result) { - jsize length = env->GetArrayLength(result); - for (jsize i = 0; i < length; i++) { - jobject item = env->GetObjectArrayElement(result, i); - - outVirtualKeyDefinitions.add(); - outVirtualKeyDefinitions.editTop().scanCode = - int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.scanCode)); - outVirtualKeyDefinitions.editTop().centerX = - int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.centerX)); - outVirtualKeyDefinitions.editTop().centerY = - int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.centerY)); - outVirtualKeyDefinitions.editTop().width = - int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.width)); - outVirtualKeyDefinitions.editTop().height = - int32_t(env->GetIntField(item, gVirtualKeyDefinitionClassInfo.height)); - - env->DeleteLocalRef(item); - } - env->DeleteLocalRef(result); - } - env->DeleteLocalRef(deviceNameStr); - } -} - void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { outExcludedDeviceNames.clear(); @@ -1366,36 +1318,12 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, gCallbacksClassInfo.clazz, "filterJumpyTouchEvents", "()Z"); - GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyDefinitions, gCallbacksClassInfo.clazz, - "getVirtualKeyDefinitions", - "(Ljava/lang/String;)[Lcom/android/server/InputManager$VirtualKeyDefinition;"); - GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz, "getExcludedDeviceNames", "()[Ljava/lang/String;"); GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz, "getMaxEventsPerSecond", "()I"); - // VirtualKeyDefinition - - FIND_CLASS(gVirtualKeyDefinitionClassInfo.clazz, - "com/android/server/InputManager$VirtualKeyDefinition"); - - GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.scanCode, gVirtualKeyDefinitionClassInfo.clazz, - "scanCode", "I"); - - GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.centerX, gVirtualKeyDefinitionClassInfo.clazz, - "centerX", "I"); - - GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.centerY, gVirtualKeyDefinitionClassInfo.clazz, - "centerY", "I"); - - GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.width, gVirtualKeyDefinitionClassInfo.clazz, - "width", "I"); - - GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.height, gVirtualKeyDefinitionClassInfo.clazz, - "height", "I"); - // InputWindow FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow"); diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp index 6ec223b..097b109 100644 --- a/tools/validatekeymaps/Main.cpp +++ b/tools/validatekeymaps/Main.cpp @@ -16,6 +16,7 @@ #include <ui/KeyCharacterMap.h> #include <ui/KeyLayoutMap.h> +#include <ui/VirtualKeyMap.h> #include <utils/String8.h> #include <stdio.h> @@ -30,6 +31,7 @@ enum FileType { FILETYPE_UNKNOWN, FILETYPE_KEYLAYOUT, FILETYPE_KEYCHARACTERMAP, + FILETYPE_VIRTUALKEYDEFINITION, }; @@ -37,8 +39,10 @@ static void usage() { fprintf(stderr, "Keymap Validation Tool\n\n"); fprintf(stderr, "Usage:\n"); fprintf(stderr, - " %s [FILENAME.kl] [FILENAME.kcm] [...]\n" - " Validates the specified key layout and/or key character map files.\n\n", gProgName); + " %s [*.kl] [*.kcm] [virtualkeys.*] [...]\n" + " Validates the specified key layouts, key character maps \n" + " or virtual key definitions.\n\n", + gProgName); } static FileType getFileType(const char* filename) { @@ -51,6 +55,11 @@ static FileType getFileType(const char* filename) { return FILETYPE_KEYCHARACTERMAP; } } + + if (strstr(filename, "virtualkeys.")) { + return FILETYPE_VIRTUALKEYDEFINITION; + } + return FILETYPE_UNKNOWN; } @@ -60,7 +69,7 @@ static bool validateFile(const char* filename) { FileType fileType = getFileType(filename); switch (fileType) { case FILETYPE_UNKNOWN: - fprintf(stderr, "File extension must be .kl or .kcm.\n\n"); + fprintf(stderr, "Supported file types: *.kl, *.kcm, virtualkeys.*\n\n"); return false; case FILETYPE_KEYLAYOUT: { @@ -82,6 +91,16 @@ static bool validateFile(const char* filename) { } break; } + + case FILETYPE_VIRTUALKEYDEFINITION: { + VirtualKeyMap* map; + status_t status = VirtualKeyMap::load(String8(filename), &map); + if (status) { + fprintf(stderr, "Error %d parsing virtual key definition file.\n\n", status); + return false; + } + break; + } } fputs("No errors.\n\n", stdout); |