|  | // | 
|  | // Copyright 2010 The Android Open Source Project | 
|  | // | 
|  | // Provides a pipe-based transport for native events in the NDK. | 
|  | // | 
|  | #define LOG_TAG "Input" | 
|  |  | 
|  | //#define LOG_NDEBUG 0 | 
|  |  | 
|  | #define DEBUG_PROBE 0 | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <unistd.h> | 
|  | #include <ctype.h> | 
|  |  | 
|  | #include <ui/Input.h> | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | static const char* CONFIGURATION_FILE_DIR[] = { | 
|  | "idc/", | 
|  | "keylayout/", | 
|  | "keychars/", | 
|  | }; | 
|  |  | 
|  | static const char* CONFIGURATION_FILE_EXTENSION[] = { | 
|  | ".idc", | 
|  | ".kl", | 
|  | ".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 (!isValidNameChar(ch)) { | 
|  | ch = '_'; | 
|  | } | 
|  | path.append(&ch, 1); | 
|  | } | 
|  | path.append(CONFIGURATION_FILE_EXTENSION[type]); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | path.setTo(getenv("ANDROID_ROOT")); | 
|  | path.append("/usr/"); | 
|  | appendInputDeviceConfigurationFileRelativePath(path, name, type); | 
|  | #if DEBUG_PROBE | 
|  | LOGD("Probing for system provided input device configuration file: path='%s'", path.string()); | 
|  | #endif | 
|  | if (!access(path.string(), R_OK)) { | 
|  | #if DEBUG_PROBE | 
|  | LOGD("Found"); | 
|  | #endif | 
|  | return path; | 
|  | } | 
|  |  | 
|  | // Search user repository. | 
|  | // TODO Should only look here if not in safe mode. | 
|  | path.setTo(getenv("ANDROID_DATA")); | 
|  | path.append("/system/devices/"); | 
|  | appendInputDeviceConfigurationFileRelativePath(path, name, type); | 
|  | #if DEBUG_PROBE | 
|  | LOGD("Probing for system user input device configuration file: path='%s'", path.string()); | 
|  | #endif | 
|  | if (!access(path.string(), R_OK)) { | 
|  | #if DEBUG_PROBE | 
|  | LOGD("Found"); | 
|  | #endif | 
|  | return path; | 
|  | } | 
|  |  | 
|  | // Not found. | 
|  | #if DEBUG_PROBE | 
|  | LOGD("Probe failed to find input device configuration file: name='%s', type=%d", | 
|  | name.string(), type); | 
|  | #endif | 
|  | return String8(); | 
|  | } | 
|  |  | 
|  |  | 
|  | // --- InputEvent --- | 
|  |  | 
|  | void InputEvent::initialize(int32_t deviceId, int32_t source) { | 
|  | mDeviceId = deviceId; | 
|  | mSource = source; | 
|  | } | 
|  |  | 
|  | void InputEvent::initialize(const InputEvent& from) { | 
|  | mDeviceId = from.mDeviceId; | 
|  | mSource = from.mSource; | 
|  | } | 
|  |  | 
|  | // --- KeyEvent --- | 
|  |  | 
|  | bool KeyEvent::hasDefaultAction(int32_t keyCode) { | 
|  | switch (keyCode) { | 
|  | case AKEYCODE_HOME: | 
|  | case AKEYCODE_BACK: | 
|  | case AKEYCODE_CALL: | 
|  | case AKEYCODE_ENDCALL: | 
|  | case AKEYCODE_VOLUME_UP: | 
|  | case AKEYCODE_VOLUME_DOWN: | 
|  | case AKEYCODE_VOLUME_MUTE: | 
|  | case AKEYCODE_POWER: | 
|  | case AKEYCODE_CAMERA: | 
|  | case AKEYCODE_HEADSETHOOK: | 
|  | case AKEYCODE_MENU: | 
|  | case AKEYCODE_NOTIFICATION: | 
|  | case AKEYCODE_FOCUS: | 
|  | case AKEYCODE_SEARCH: | 
|  | case AKEYCODE_MEDIA_PLAY: | 
|  | case AKEYCODE_MEDIA_PAUSE: | 
|  | case AKEYCODE_MEDIA_PLAY_PAUSE: | 
|  | case AKEYCODE_MEDIA_STOP: | 
|  | case AKEYCODE_MEDIA_NEXT: | 
|  | case AKEYCODE_MEDIA_PREVIOUS: | 
|  | case AKEYCODE_MEDIA_REWIND: | 
|  | case AKEYCODE_MEDIA_RECORD: | 
|  | case AKEYCODE_MEDIA_FAST_FORWARD: | 
|  | case AKEYCODE_MUTE: | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool KeyEvent::hasDefaultAction() const { | 
|  | return hasDefaultAction(getKeyCode()); | 
|  | } | 
|  |  | 
|  | bool KeyEvent::isSystemKey(int32_t keyCode) { | 
|  | switch (keyCode) { | 
|  | case AKEYCODE_MENU: | 
|  | case AKEYCODE_SOFT_RIGHT: | 
|  | case AKEYCODE_HOME: | 
|  | case AKEYCODE_BACK: | 
|  | case AKEYCODE_CALL: | 
|  | case AKEYCODE_ENDCALL: | 
|  | case AKEYCODE_VOLUME_UP: | 
|  | case AKEYCODE_VOLUME_DOWN: | 
|  | case AKEYCODE_VOLUME_MUTE: | 
|  | case AKEYCODE_MUTE: | 
|  | case AKEYCODE_POWER: | 
|  | case AKEYCODE_HEADSETHOOK: | 
|  | case AKEYCODE_MEDIA_PLAY: | 
|  | case AKEYCODE_MEDIA_PAUSE: | 
|  | case AKEYCODE_MEDIA_PLAY_PAUSE: | 
|  | case AKEYCODE_MEDIA_STOP: | 
|  | case AKEYCODE_MEDIA_NEXT: | 
|  | case AKEYCODE_MEDIA_PREVIOUS: | 
|  | case AKEYCODE_MEDIA_REWIND: | 
|  | case AKEYCODE_MEDIA_RECORD: | 
|  | case AKEYCODE_MEDIA_FAST_FORWARD: | 
|  | case AKEYCODE_CAMERA: | 
|  | case AKEYCODE_FOCUS: | 
|  | case AKEYCODE_SEARCH: | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool KeyEvent::isSystemKey() const { | 
|  | return isSystemKey(getKeyCode()); | 
|  | } | 
|  |  | 
|  | void KeyEvent::initialize( | 
|  | int32_t deviceId, | 
|  | int32_t source, | 
|  | int32_t action, | 
|  | int32_t flags, | 
|  | int32_t keyCode, | 
|  | int32_t scanCode, | 
|  | int32_t metaState, | 
|  | int32_t repeatCount, | 
|  | nsecs_t downTime, | 
|  | nsecs_t eventTime) { | 
|  | InputEvent::initialize(deviceId, source); | 
|  | mAction = action; | 
|  | mFlags = flags; | 
|  | mKeyCode = keyCode; | 
|  | mScanCode = scanCode; | 
|  | mMetaState = metaState; | 
|  | mRepeatCount = repeatCount; | 
|  | mDownTime = downTime; | 
|  | mEventTime = eventTime; | 
|  | } | 
|  |  | 
|  | void KeyEvent::initialize(const KeyEvent& from) { | 
|  | InputEvent::initialize(from); | 
|  | mAction = from.mAction; | 
|  | mFlags = from.mFlags; | 
|  | mKeyCode = from.mKeyCode; | 
|  | mScanCode = from.mScanCode; | 
|  | mMetaState = from.mMetaState; | 
|  | mRepeatCount = from.mRepeatCount; | 
|  | mDownTime = from.mDownTime; | 
|  | mEventTime = from.mEventTime; | 
|  | } | 
|  |  | 
|  | // --- MotionEvent --- | 
|  |  | 
|  | void MotionEvent::initialize( | 
|  | int32_t deviceId, | 
|  | int32_t source, | 
|  | int32_t action, | 
|  | int32_t flags, | 
|  | int32_t edgeFlags, | 
|  | int32_t metaState, | 
|  | float xOffset, | 
|  | float yOffset, | 
|  | float xPrecision, | 
|  | float yPrecision, | 
|  | nsecs_t downTime, | 
|  | nsecs_t eventTime, | 
|  | size_t pointerCount, | 
|  | const int32_t* pointerIds, | 
|  | const PointerCoords* pointerCoords) { | 
|  | InputEvent::initialize(deviceId, source); | 
|  | mAction = action; | 
|  | mFlags = flags; | 
|  | mEdgeFlags = edgeFlags; | 
|  | mMetaState = metaState; | 
|  | mXOffset = xOffset; | 
|  | mYOffset = yOffset; | 
|  | mXPrecision = xPrecision; | 
|  | mYPrecision = yPrecision; | 
|  | mDownTime = downTime; | 
|  | mPointerIds.clear(); | 
|  | mPointerIds.appendArray(pointerIds, pointerCount); | 
|  | mSampleEventTimes.clear(); | 
|  | mSamplePointerCoords.clear(); | 
|  | addSample(eventTime, pointerCoords); | 
|  | } | 
|  |  | 
|  | void MotionEvent::addSample( | 
|  | int64_t eventTime, | 
|  | const PointerCoords* pointerCoords) { | 
|  | mSampleEventTimes.push(eventTime); | 
|  | mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); | 
|  | } | 
|  |  | 
|  | void MotionEvent::offsetLocation(float xOffset, float yOffset) { | 
|  | mXOffset += xOffset; | 
|  | mYOffset += yOffset; | 
|  | } | 
|  |  | 
|  | // --- InputDeviceInfo --- | 
|  |  | 
|  | InputDeviceInfo::InputDeviceInfo() { | 
|  | initialize(-1, String8("uninitialized device info")); | 
|  | } | 
|  |  | 
|  | InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : | 
|  | mId(other.mId), mName(other.mName), mSources(other.mSources), | 
|  | mKeyboardType(other.mKeyboardType), | 
|  | mMotionRanges(other.mMotionRanges) { | 
|  | } | 
|  |  | 
|  | InputDeviceInfo::~InputDeviceInfo() { | 
|  | } | 
|  |  | 
|  | void InputDeviceInfo::initialize(int32_t id, const String8& name) { | 
|  | mId = id; | 
|  | mName = name; | 
|  | mSources = 0; | 
|  | mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; | 
|  | mMotionRanges.clear(); | 
|  | } | 
|  |  | 
|  | const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(int32_t rangeType) const { | 
|  | ssize_t index = mMotionRanges.indexOfKey(rangeType); | 
|  | return index >= 0 ? & mMotionRanges.valueAt(index) : NULL; | 
|  | } | 
|  |  | 
|  | void InputDeviceInfo::addSource(uint32_t source) { | 
|  | mSources |= source; | 
|  | } | 
|  |  | 
|  | void InputDeviceInfo::addMotionRange(int32_t rangeType, float min, float max, | 
|  | float flat, float fuzz) { | 
|  | MotionRange range = { min, max, flat, fuzz }; | 
|  | addMotionRange(rangeType, range); | 
|  | } | 
|  |  | 
|  | void InputDeviceInfo::addMotionRange(int32_t rangeType, const MotionRange& range) { | 
|  | mMotionRanges.add(rangeType, range); | 
|  | } | 
|  |  | 
|  | } // namespace android |