db360642ed
Use Vendor ID, Product ID and optionally the Version to locate keymaps and configuration files for external devices. Moved virtual key definition parsing to native code so that EventHub can identify touch screens with virtual keys and load the appropriate key layout file. Cleaned up a lot of old code in EventHub. Fixed a regression in ViewRoot's fallback event handling. Fixed a minor bug in FileMap that caused it to try to munmap or close invalid handled when released if the attempt to map the file failed. Added a couple of new String8 conveniences for formatting strings. Modified Tokenizer to fall back to open+read when mmap fails since we can't mmap sysfs files as needed to open the virtual key definition files in /sys/board_properties/. Change-Id: I6ca5e5f9547619fd082ddac47e87ce185da69ee6
330 lines
8.9 KiB
C++
330 lines
8.9 KiB
C++
//
|
|
// 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
|