Android输入设备处理流程 2010-11-19 14:50 Android系统硬件的访问是通过HAL(Hardware Abstract Layer)来进行的,HAL就起到来Hardware adapter的作用。对于输入设备,如KeyPad、TouchPanel等,Android用EventHub具体的对其进行了封装。 输入设备驱动程序对用户空间应用程序提供一些设备文件,这些设备文件放在/dev/input里面。 1. EventHub扫描/dev/input下所有设备文件,并打开它们。 - bool EventHub::openPlatformInput(void)
-
{
-
...
-
mFDCount = 1;
-
mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
-
mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
-
mFDs[0].events = POLLIN;
-
mDevices[0] = NULL;
-
-
res = scan_dir(device_path);
-
...
-
return true;
-
}
-
-
int EventHub::scan_dir(const char *dirname)
-
{
-
char devname[PATH_MAX];
-
char *filename;
-
DIR *dir;
-
struct dirent *de;
-
dir = opendir(dirname);
-
if(dir == NULL)
-
return -1;
-
strcpy(devname, dirname);
-
filename = devname + strlen(devname);
-
*filename++ = '/';
-
while((de = readdir(dir)))
-
{
-
if(de->d_name[0] == '.' &&
-
(de->d_name[1] == '\0' ||
-
(de->d_name[1] == '.' && de->d_name[2] == '\0')))
-
continue;
-
strcpy(filename, de->d_name);
-
open_device(devname);
-
}
-
closedir(dir);
-
return 0;
-
}
-
-
open_device(devname)
-
{
-
open(...)
-
ioctl(...)
-
}
-
EventHub对外提供了一个函数用于从输入设备文件中读取数据。
-
-
bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
-
int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
-
int32_t* outValue, nsecs_t* outWhen)
-
{
-
...
-
while(1)
-
{
-
-
// First, 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->id, device->path.string());
-
mClosingDevices = device->next;
-
*outDeviceId = device->id;
-
if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
-
*outType = DEVICE_REMOVED;
-
delete device;
-
return true;
-
}
-
-
if (mOpeningDevices != NULL)
-
{
-
device_t* device = mOpeningDevices;
-
LOGV("Reporting device opened: id=0x%x, name=%s\n",
-
device->id, device->path.string());
-
mOpeningDevices = device->next;
-
*outDeviceId = device->id;
-
if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
-
*outType = DEVICE_ADDED;
-
return true;
-
}
-
-
release_wake_lock(WAKE_LOCK_ID);
-
-
pollres = poll(mFDs, mFDCount, -1);
-
-
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
-
-
if (pollres <= 0)
-
{
-
if (errno != EINTR)
-
{
-
LOGW("select failed (errno=%d)\n", errno);
-
usleep(100000);
-
}
-
continue;
-
}
-
-
for(i = 1; i < mFDCount; i++)
-
{
-
if(mFDs[i].revents)
-
{
-
LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
-
if(mFDs[i].revents & POLLIN)
-
{
-
res = read(mFDs[i].fd, &iev, sizeof(iev));
-
if (res == sizeof(iev))
-
{
-
LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
-
mDevices[i]->path.string(),
-
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
-
iev.type, iev.code, iev.value);
-
*outDeviceId = mDevices[i]->id;
-
if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
-
*outType = iev.type;
-
*outScancode = iev.code;
-
if (iev.type == EV_KEY)
-
{
-
err = mDevices[i]->layoutMap->map(iev.code, outKeycode, outFlags);
-
LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n",
-
iev.code, *outKeycode, *outFlags, err);
-
if (err != 0)
-
{
-
*outKeycode = 0;
-
*outFlags = 0;
-
}
-
}
-
else
-
{
-
*outKeycode = iev.code;
-
}
-
*outValue = iev.value;
-
*outWhen = s2ns(iev.time.tv_sec) + us2ns(iev.time.tv_usec);
-
return true;
-
}
-
else
-
{
-
if (res<0)
-
{
-
LOGW("could not get event (errno=%d)", errno);
-
}
-
else
-
{
-
LOGE("could not get event (wrong size: %d)", res);
-
}
-
continue;
-
}
-
}
-
}
-
}
-
...
-
}
对于按键事件,调用mDevices[i]->layoutMap->map进行映射。映射实际是由 KeyLayoutMap::map完成的,KeyLayoutMap类里读取配置文件qwerty.kl,由配置文件qwerty.kl决定键值的映射 关系。你可以通过修改./development/emulator/keymaps/qwerty.kl来改变键值的映射关系。 2. JNI函数 在frameworks/base/services/jni/com_android_server_KeyInputQueue.cpp文件 中,向JAVA提供了函数android_server_KeyInputQueue_readEvent,用于读取输入设备事件。 |
|