編輯:關於Android編程
分析一下 Android 是如何讀取按鍵及Touch Panel 的驅動的。主要在
$(ANDROID_DIR)/frameworks/base/libs/ui/EventHub.cpp
這個文件中,這是在 HAL 層,將一步步分析 Android 上層是如何接受事件的。
一, 先看一下 Android HAL
Class EventHub 在 $(ANDROID_DIR)/frameworks/base/include/ui/eventhub.h 定義.
i. scan_dir(const char *dirname) // dirname = "/dev/input"
掃描 dirname 目錄, 該目錄下有 event0, event1 ..., 等設備.
ii. open_device(devname);
打開 /dev/input/event0, /dev/input/event1 等設備.
這裡以打開 /dev/input/event0 設備為例, 分析按鍵的底層處理.
for (attempt = 0; attempt < 10; attempt++) {
fd = open(deviceName, O_RDWR);
if (fd >= 0) break;
usleep(100);
}
首先會打開傳進來的設備. 然後會獲取version, id等信息.
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';
}
獲取 driver name, 在這裡也就是 /dev/input/evevnt0, 也就是要到 Driver 裡面去讀取.
這個名字很重要, 之後要與 keyboard map 相匹配.
這裡返回的值是: name = "wayland_m_ebook_key_input"
為什麼會返回這個值? 請看 event0 的 linux driver.
wayland_m_ebook_keypad_probe() 函數中,有以下語句:
gpio_key_input->name = "wayland_m_ebook_key_input".
所以這個值是在這個時候設置的。
int devid = 0;
while (devid < mNumDevicesById) {
if (mDevicesById[devid].device == NULL) {
break;
}
devid++;
}
if (devid >= mNumDevicesById) {
device_ent* new_devids = (device_ent*)realloc(mDevicesById,
sizeof(mDevicesById[0]) * (devid + 1));
if (new_devids == NULL) {
LOGE("out of memory");
return -1;
}
mDevicesById = new_devids;
mNumDevicesById = devid+1;
mDevicesById[devid].device = NULL;
mDevicesById[devid].seq = 0;
}
分配 new device, 將 device 信息保存至 mDeviceById[] 數組中.
mNumDevicesById: device 的數量
mDevicesById: devive 的信息
new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
為 new_mFDs, mFDs 分配空間, 以備之後保存每個 event(x) 的fd.
mFDs[mFDCount].fd = fd;
mFDs[mFDCount].events = POLLIN;
將 fd 放到 mFDs 數組中.
// See if this is a keyboard, and classify it.
uint8_t key_bitmask[(KEY_MAX+1)/8];
memset(key_bitmask, 0, sizeof(key_bitmask));
LOGV("Getting keys...");
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
//LOGI("MAP\n");
//for (int i=0; i<((KEY_MAX+1)/8); i++) {
// LOGI("%d: 0x%02x\n", i, key_bitmask[i]);
//}
for (int i=0; i<((BTN_MISC+7)/8); i++) {
if (key_bitmask[i] != 0) {
device->classes |= CLASS_KEYBOARD;
break;
}
}
if ((device->classes & CLASS_KEYBOARD) != 0) {
device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
if (device->keyBitmask != NULL) {
memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
} else {
delete device;
LOGE("out of memory allocating key bitmask");
return -1;
}
}
}
如果是 keyboard 的設備.
if (test_bit(BTN_TOUCH, key_bitmask)) {
uint8_t abs_bitmask[(ABS_MAX+1)/8];
memset(abs_bitmask, 0, sizeof(abs_bitmask));
LOGV("Getting absolute controllers...");
if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0)
{
if (test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
device->classes |= CLASS_TOUCHSCREEN;
}
}
}
繼續分析 Android 是如何進行 keyboard 映射的:
char tmpfn[sizeof(name)];
char keylayoutFilename[300];
// a more descriptive name
device->name = name;
// replace all the spaces with underscores
strcpy(tmpfn, name);
for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
*p = '_';
// find the .kl file we need for this device
const char* root = getenv("ANDROID_ROOT");
snprintf(keylayoutFilename, sizeof(keylayoutFilename),
"%s/usr/keylayout/%s.kl", root, tmpfn);
bool defaultKeymap = false;
if (access(keylayoutFilename, R_OK)) {
解決AngualrJS頁面刷新導致異常顯示問題 緒 俗話說,細節決定成敗,編程亦是如此。編程過程中我們可能會不自覺的忽視一些細節問題,殊不知,這些細節
在使用android類的手寫應用時,整體上都有這樣一個印象:android的手寫不流暢、不自然,和蘋果應用比起來相差太遠。本文結合作者親身經歷,介紹一下有效提高手寫流暢度
Android畫布翻轉是個利器,尤其在圖像處理上,不需要數組的轉置顛倒一堆線性變化就可以輕松實現原點的改變。就像醬紫,開始的時候,畫布妹妹是和顯示區哥哥重疊在一起的,默契
Android的彈窗效果有很多種,就最簡單而言,就可以調用一個AlertDialog彈窗顯示,可是要自定義彈窗效果有以下這種方法,就我個人而言感覺挺方便的,適用性也挺廣的