#include "evdev.h" #include #include #include #include static int tap_timeout = 2000; // 3s void evdev_init(evdev_drv_state_t *state, char* dev_path) { LV_LOG_INFO("Opening evdev %s!", dev_path); state->fd = open(dev_path, O_RDWR | O_NOCTTY | O_NDELAY); if(state->fd == -1) { perror("unable to open evdev interface:"); return; } fcntl(state->fd, F_SETFL, O_ASYNC | O_NONBLOCK); state->root_x = 0; state->root_y = 0; state->key_val = 0; state->button = LV_INDEV_STATE_REL; } void evdev_init_keypad(evdev_drv_state_t *state, char* dev_path) { evdev_init(state, dev_path); state->key_raw = 0; state->timestamp_pr = 0; state->pressed_streak = 0; } int evdev_stop(evdev_drv_state_t *state) { return close(state->fd); } static char get_key_from_map(multitap_keymap_t *key_map, int code, u_int32_t pcount) { int i = 0; while (key_map[i].key != PKEY_UNDEFINED) { if (key_map[i].key == code) { return key_map[i].sequence[pcount % strlen(key_map[i].sequence)]; } i++; } return '\0'; } static int process_multitap(evdev_drv_state_t *state, lv_indev_drv_t *drv, lv_indev_data_t *data, lv_indev_t *desc, struct input_event *in) { if (in->value == 1) { // OnPress update counters if (lv_tick_elaps(state->timestamp_pr) > tap_timeout) { state->pressed_streak = 0; } else { if (state->key_raw == in->code) { state->pressed_streak++; } else { state->pressed_streak = 0; } } state->key_raw = in->code; lv_group_t *g = desc->group; if (g == NULL) return 0; lv_obj_t *focus_obj = lv_group_get_focused(g); if(focus_obj == NULL) return 0; if(!lv_obj_check_type(focus_obj, &lv_textarea_class)) return 0; if (state->pressed_streak != 0 && in->value == 0) { lv_textarea_del_char(focus_obj); } } state->timestamp_pr = lv_tick_get(); return get_key_from_map(input_get_active_keymap(), in->code, state->pressed_streak); } int handle_special_keys(evdev_drv_state_t *state, struct input_event *in) { switch(in->code) { case KEY_BACKSPACE: case KEY_ENTER: case KEY_PREVIOUS: case KEY_NEXT: case KEY_UP: case KEY_LEFT: case KEY_RIGHT: case KEY_DOWN: case KEY_TAB: state->pressed_streak = 0; state->key_raw = 0; } switch(in->code) { case KEY_BACKSPACE: return LV_KEY_BACKSPACE; break; case KEY_ENTER: return LV_KEY_ENTER; break; case KEY_PREVIOUS: return LV_KEY_PREV; break; case KEY_NEXT: return LV_KEY_NEXT; break; case KEY_UP: return LV_KEY_UP; break; case KEY_LEFT: return LV_KEY_LEFT; break; case KEY_RIGHT: return LV_KEY_RIGHT; break; case KEY_DOWN: return LV_KEY_DOWN; break; case KEY_TAB: return LV_KEY_NEXT; break; default: return 0; } } void evdev_read(evdev_drv_state_t *state, lv_indev_drv_t *drv, lv_indev_t *desc, lv_indev_data_t *data) { struct input_event in; while(read(state->fd, &in, sizeof(struct input_event)) > 0) { if(in.type == EV_REL) { if(in.code == REL_X) #if EVDEV_SWAP_AXES state->root_y += in.value; #else state->root_x += in.value; #endif else if(in.code == REL_Y) #if EVDEV_SWAP_AXES state->root_x += in.value; #else state->root_y += in.value; #endif } else if(in.type == EV_ABS) { if(in.code == ABS_X) { #if EVDEV_SWAP_AXES state->root_y = in.value; #else state->root_x = in.value; #endif } else if(in.code == ABS_Y) { #if EVDEV_SWAP_AXES state->root_x = in.value; #else state->root_y = in.value; #endif } else if(in.code == ABS_MT_POSITION_X) { #if EVDEV_SWAP_AXES state->root_y = in.value; #else state->root_x = in.value; #endif } else if(in.code == ABS_MT_POSITION_Y) { #if EVDEV_SWAP_AXES state->root_x = in.value; #else state->root_y = in.value; #endif } else if(in.code == ABS_MT_TRACKING_ID) { if(in.value == -1) state->button = LV_INDEV_STATE_REL; else if(in.value == 0) state->button = LV_INDEV_STATE_PR; } } else if(in.type == EV_KEY) { if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) { if(in.value == 0) state->button = LV_INDEV_STATE_REL; else if(in.value == 1) state->button = LV_INDEV_STATE_PR; } else if(drv->type == LV_INDEV_TYPE_KEYPAD) { LV_LOG_WARN("Got key %d.", in.code); data->key = handle_special_keys(state, &in); if (data->key == 0) { data->key = process_multitap(state, drv, data, desc, &in); } if (data->key != 0) { /* Only record button state when actual output is produced to prevent widgets from refreshing */ data->state = (in.value) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; } state->key_val = data->key; state->button = data->state; return; } } } if(drv->type == LV_INDEV_TYPE_KEYPAD) { /* No data retrieved */ data->key = state->key_val; data->state = state->button; return; } if(drv->type != LV_INDEV_TYPE_POINTER) return ; /*Store the collected data*/ data->point.x = state->root_x; data->point.y = state->root_y; data->state = state->button; if(data->point.x < 0) data->point.x = 0; if(data->point.y < 0) data->point.y = 0; if(data->point.x >= drv->disp->driver->hor_res) data->point.x = drv->disp->driver->hor_res - 1; if(data->point.y >= drv->disp->driver->ver_res) data->point.y = drv->disp->driver->ver_res - 1; return ; }