編輯:關於Android編程
struct input_dev { const char *name; //input 設備名稱 ... struct input_id id; //與input_handler匹配用的id unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //設備支持的事件類型 unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //按鍵事件支持的子事件類型 unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //相對坐標事件支持的子事件類型 unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //絕對坐標事件支持的子事件類型 unsigned int keycodemax; unsigned int keycodesize; void *keycode; int (*setkeycode)(struct input_dev *dev, const struct input_keymap_entry *ke, unsigned int *old_keycode); int (*getkeycode)(struct input_dev *dev, struct input_keymap_entry *ke); struct ff_device *ff; ... int (*open)(struct input_dev *dev); void (*close)(struct input_dev *dev); int (*flush)(struct input_dev *dev, struct file *file); int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); struct input_handle __rcu *grab; //當前占有該設備的handle struct device dev; struct list_head h_list; //該鏈表頭用於鏈接該設備所關聯的input_handle struct list_head node; //該鏈表頭用於將設備鏈接到input_dev_list ... }; struct input_handler { ... void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); void (*events)(struct input_handle *handle, const struct input_value *vals, unsigned int count); bool (*match)(struct input_handler *handler, struct input_dev *dev); int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); void (*disconnect)(struct input_handle *handle); const struct input_device_id *id_table; //與input_dev匹配用的id struct list_head h_list; //用於鏈接和該handler相關的handle struct list_head node; //用於將該handler鏈入input_handler_list ... }; struct input_handle { int open; const char *name; struct input_dev *dev; //指向所屬的input_dev struct input_handler *handler; //指向所屬的input_handler struct list_head d_node; //用於鏈入所指向的input_dev的handle鏈表 struct list_head h_node; //用於鏈入所指向的input_handler的handle鏈表 };三個結構體可以這樣理解,input_dev可以作為輸入設備的描述,input_handler可作為事件的處理函數(類似如中斷處理)
int input_register_device(struct input_dev *dev) { struct input_devres *devres = NULL; struct input_handler *handler; /* Every input device generates EV_SYN/SYN_REPORT events. */ __set_bit(EV_SYN, dev->evbit); //設置支持同步事件,input設備全部默認支持同步事件 error = device_add(&dev->dev); ... list_add_tail(&dev->node, &input_dev_list); //將設備添加到input_dev_list中 list_for_each_entry(handler, &input_handler_list, node) input_attach_handler(dev, handler); input_wakeup_procfs_readers(); ... } static int input_attach_handler(struct input_dev *dev, struct input_handler *handler) { ... id = input_match_device(handler, dev); error = handler->connect(handler, dev, id); ... } static const struct input_device_id *input_match_device(struct input_handler *handler, struct input_dev *dev) { const struct input_device_id *id; for (id = handler->id_table; id->flags || id->driver_info; id++) { if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) if (id->bustype != dev->id.bustype) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) if (id->vendor != dev->id.vendor) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) if (id->product != dev->id.product) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) if (id->version != dev->id.version) continue; if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX)) continue; if (!bitmap_subset(id->keybit, dev->keybit, KEY_MAX)) continue; if (!bitmap_subset(id->relbit, dev->relbit, REL_MAX)) continue; if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX)) continue; if (!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX)) continue; if (!bitmap_subset(id->ledbit, dev->ledbit, LED_MAX)) continue; if (!bitmap_subset(id->sndbit, dev->sndbit, SND_MAX)) continue; if (!bitmap_subset(id->ffbit, dev->ffbit, FF_MAX)) continue; if (!bitmap_subset(id->swbit, dev->swbit, SW_MAX)) continue; //將設備id與handler的id進行匹配,成功直接返回ID if (!handler->match || handler->match(handler, dev)) return id; } return NULL; }file:kernel-3.18/drivers/input/evdev.c
static struct input_handler evdev_handler = { .event = evdev_event, .events = evdev_events, .connect = evdev_connect, .disconnect = evdev_disconnect, .legacy_minors = true, .minor = EVDEV_MINOR_BASE, .name = "evdev", .id_table = evdev_ids, };從上面input_handler的初始化可以看出handler->match為null,所以上面的input_match_device如果前面的條件
static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { struct evdev *evdev; //定義一個evdev結構體指針 minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true); INIT_LIST_HEAD(&evdev->client_list); dev_no = minor; /* Normalize device number if it falls into legacy range */ if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS) dev_no -= EVDEV_MINOR_BASE; dev_set_name(&evdev->dev, "event%d", dev_no); //設置設備名為eventxx evdev->handle.dev = input_get_device(dev); evdev->handle.name = dev_name(&evdev->dev); //這步最關鍵將handler賦值為evdev->handle.handler,完成input_dev和hander的掛接 evdev->handle.handler = handler; evdev->handle.private = evdev; evdev->dev.devt = MKDEV(INPUT_MAJOR, minor); evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; evdev->dev.release = evdev_free; device_initialize(&evdev->dev); error = input_register_handle(&evdev->handle); cdev_init(&evdev->cdev, &evdev_fops); //綁定file操作函數 evdev->cdev.kobj.parent = &evdev->dev.kobj; error = cdev_add(&evdev->cdev, evdev->dev.devt, 1); error = device_add(&evdev->dev);//注冊一個設備到內核 ... return 0; }3.上報鍵值的實現
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) { input_event(dev, EV_KEY, code, !!value); } file:kernel-3.18/drivers/input/input.c void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { input_handle_event(dev, type, code, value); } static void input_handle_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { int disposition; disposition = input_get_disposition(dev, type, code, &value); if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) dev->event(dev, type, code, value); if (!dev->vals) return; if (disposition & INPUT_PASS_TO_HANDLERS) { struct input_value *v; if (disposition & INPUT_SLOT) { v = &dev->vals[dev->num_vals++]; v->type = EV_ABS; v->code = ABS_MT_SLOT; v->value = dev->mt->slot; } v = &dev->vals[dev->num_vals++]; v->type = type; v->code = code; v->value = value; } if (disposition & INPUT_FLUSH) { if (dev->num_vals >= 2) input_pass_values(dev, dev->vals, dev->num_vals); dev->num_vals = 0; } else if (dev->num_vals >= dev->max_vals - 2) { dev->vals[dev->num_vals++] = input_value_sync; input_pass_values(dev, dev->vals, dev->num_vals); dev->num_vals = 0; } } static void input_pass_values(struct input_dev *dev, struct input_value *vals, unsigned int count) { struct input_handle *handle; struct input_value *v; if (!count) return; rcu_read_lock(); handle = rcu_dereference(dev->grab); if (handle) { count = input_to_handler(handle, vals, count); } else { list_for_each_entry_rcu(handle, &dev->h_list, d_node) if (handle->open) count = input_to_handler(handle, vals, count); } rcu_read_unlock(); add_input_randomness(vals->type, vals->code, vals->value); /* trigger auto repeat for key events */ for (v = vals; v != vals + count; v++) { if (v->type == EV_KEY && v->value != 2) { if (v->value) input_start_autorepeat(dev, v->code); else input_stop_autorepeat(dev); } } } static unsigned int input_to_handler(struct input_handle *handle, struct input_value *vals, unsigned int count) { struct input_handler *handler = handle->handler; struct input_value *end = vals; struct input_value *v; for (v = vals; v != vals + count; v++) { if (handler->filter && handler->filter(handle, v->type, v->code, v->value)) continue; if (end != v) *end = *v; end++; } count = end - vals; if (!count) return 0; if (handler->events) handler->events(handle, vals, count); else if (handler->event) for (v = vals; v != end; v++) handler->event(handle, v->type, v->code, v->value); return count; }file:kernel-3.18/drivers/input/evdev.c
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct input_value vals[] = { { type, code, value } }; evdev_events(handle, vals, 1); } static void evdev_pass_values(struct evdev_client *client, const struct input_value *vals, unsigned int count, ktime_t mono, ktime_t real) { struct evdev *evdev = client->evdev; const struct input_value *v; struct input_event event; bool wakeup = false; if (client->revoked) return; event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? mono : real); /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); for (v = vals; v != vals + count; v++) { event.type = v->type; event.code = v->code; event.value = v->value; __pass_event(client, &event); if (v->type == EV_SYN && v->code == SYN_REPORT) wakeup = true; } spin_unlock(&client->buffer_lock); if (wakeup) wake_up_interruptible(&evdev->wait); } static void __pass_event(struct evdev_client *client, const struct input_event *event) { client->buffer[client->head++] = *event; client->head &= client->bufsize - 1; if (unlikely(client->head == client->tail)) { /* * This effectively "drops" all unconsumed events, leaving * EV_SYN/SYN_DROPPED plus the newest event in the queue. */ client->tail = (client->head - 2) & (client->bufsize - 1); //將需要上報的數據存放在buffer中 client->buffer[client->tail].time = event->time; client->buffer[client->tail].type = EV_SYN; client->buffer[client->tail].code = SYN_DROPPED; client->buffer[client->tail].value = 0; client->packet_head = client->tail; if (client->use_wake_lock) wake_unlock(&client->wake_lock); } if (event->type == EV_SYN && event->code == SYN_REPORT) { client->packet_head = client->head; if (client->use_wake_lock) wake_lock(&client->wake_lock); kill_fasync(&client->fasync, SIGIO, POLL_IN); } }4.讀取鍵值的實現
static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; struct input_event event; size_t read = 0; int error; if (count != 0 && count < input_event_size()) return -EINVAL; for (;;) { if (!evdev->exist || client->revoked) return -ENODEV; if (client->packet_head == client->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; /* * count == 0 is special - no IO is done but we check * for error conditions (see above). */ if (count == 0) break; while (read + input_event_size() <= count && evdev_fetch_next_event(client, &event)) { if (input_event_to_user(buffer + read, &event)) return -EFAULT; read += input_event_size(); } if (read) break; if (!(file->f_flags & O_NONBLOCK)) { error = wait_event_interruptible(evdev->wait, client->packet_head != client->tail || !evdev->exist || client->revoked); if (error) return error; } } return read; }file:kernel-3.18/drivers/input/input-compat.c
int input_event_to_user(char __user *buffer, const struct input_event *event) { if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) { struct input_event_compat compat_event; compat_event.time.tv_sec = event->time.tv_sec; compat_event.time.tv_usec = event->time.tv_usec; compat_event.type = event->type; compat_event.code = event->code; compat_event.value = event->value; if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat))) return -EFAULT; } else { //最終使用copy_to_user將數據上傳到用戶空間 if (copy_to_user(buffer, event, sizeof(struct input_event))) return -EFAULT; } return 0; }5.小結
在Android應用的開發中,ListView是最常用的一個列表顯示控件,微博,聯系人啊,反正只要涉及多數據展示的情況,都會用到ListView(另外就是GridView
圓角按鈕,或布局可以在xml文件中實現,但也可以使用圖片直接達到所需的效果,以前版本的微信就使用了這種方法。 實現效果圖: 不得不說,這種做法還是比較方便的。 源
效果圖: 步驟一:分析變量信息 //-------------必須給的數據相關------------- private String[
1、概述 相信大家對AsyncTask都不陌生,對於執行耗時任務,然後更新UI是一把利器,當然也是替代Thread + Handler 的一種方式。如果你對