/* * Copyright (c) 2019 Actions Semiconductor Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @file input manager interface */ #include #include #include #include #include #include #include #include #include #include #include #define CONFIG_READ_DIRCT 1 /* Drag threshold in pixels */ #define POINTER_SCROLL_LIMIT 10 /* Gesture threshold in pixels */ #define POINTER_GESTURE_LIMIT 50 /* Gesture min velocity at release before swipe (pixels) */ #define POINTER_GESTURE_MIN_VELOCITY 3 #ifndef ABS # define ABS(x) (((x) >= 0) ? (x) : -(x)) #endif #ifdef CONFIG_INPUT_DEV_ACTS_TP_KEY #ifndef CONFIG_READ_DIRCT K_MSGQ_DEFINE(pointer_scan_msgq, sizeof(input_dev_data_t), 10, 4); #endif static uint32_t s_supported_gestures; static void pointer_gesture_detect(input_drv_t *drv, input_dev_data_t *data) { static point_t scroll_sum; static point_t gesture_sum; static input_dev_data_t prev = { .point.x = 0, .point.y = 0, .state = INPUT_DEV_STATE_REL, .gesture_dir = 0, .scroll_dir = 0, }; point_t vec; uint8_t gesture_dir = 0; uint8_t scroll_dir = 0; if (prev.state == INPUT_DEV_STATE_REL) goto out_exit; if (data->state == INPUT_DEV_STATE_PR) { vec.x = data->point.x - prev.point.x; vec.y = data->point.y - prev.point.y; scroll_sum.x += vec.x; scroll_sum.y += vec.y; if (ABS(scroll_sum.x) > drv->scroll_limit || ABS(scroll_sum.y) > drv->scroll_limit) { if (ABS(scroll_sum.x) >= ABS(scroll_sum.y)) { scroll_dir = (scroll_sum.x > 0) ? GESTURE_DROP_RIGHT : GESTURE_DROP_LEFT; } else { scroll_dir = (scroll_sum.y > 0) ? GESTURE_DROP_DOWN : GESTURE_DROP_UP; } } if (ABS(vec.x) < drv->gesture_min_velocity && ABS(vec.y) < drv->gesture_min_velocity) { gesture_sum.x = 0; gesture_sum.y = 0; } gesture_sum.x += vec.x; gesture_sum.y += vec.y; if (ABS(gesture_sum.x) > drv->gesture_limit || ABS(gesture_sum.y) > drv->gesture_limit) { if (ABS(gesture_sum.x) >= ABS(gesture_sum.y)) { gesture_dir = (gesture_sum.x > 0) ? GESTURE_DROP_RIGHT : GESTURE_DROP_LEFT; } else { gesture_dir = (gesture_sum.y > 0) ? GESTURE_DROP_DOWN : GESTURE_DROP_UP; } } } else if (data->state == INPUT_DEV_STATE_REL) { gesture_sum.x = 0; gesture_sum.y = 0; scroll_sum.x = 0; scroll_sum.y = 0; } out_exit: data->gesture_dir = gesture_dir; data->scroll_dir = scroll_dir; prev = *data; } static void pointer_scan_callback(struct device *dev, struct input_value *val) { #ifndef CONFIG_READ_DIRCT input_dev_data_t data = { .point.x = val->point.loc_x, .point.y = val->point.loc_y, .state = (val->point.pessure_value == 1)? INPUT_DEV_STATE_PR : INPUT_DEV_STATE_REL, .gesture = val->point.gesture, }; if (k_msgq_put(&pointer_scan_msgq, &data, K_NO_WAIT) != 0) { SYS_LOG_ERR("Could put input data into queue"); } #endif } static bool pointer_scan_read(input_drv_t *drv, input_dev_data_t *data) { #if CONFIG_READ_DIRCT static input_dev_state_t last_state = INPUT_DEV_STATE_REL; struct input_value val; memset(&val, 0, sizeof(struct input_value)); input_dev_inquiry(drv->input_dev, &val); data->point.x = val.point.loc_x; data->point.y = val.point.loc_y; data->state = (val.point.pessure_value == 1)? INPUT_DEV_STATE_PR : INPUT_DEV_STATE_REL; if (s_supported_gestures == 0) { pointer_gesture_detect(drv, data); } else { data->gesture_dir = val.point.gesture; data->scroll_dir = val.point.gesture; } if (last_state != data->state) { input_manager_boost(data->state == INPUT_DEV_STATE_PR); last_state = data->state; #ifdef CONFIG_SYS_WAKELOCK if (data->state == INPUT_DEV_STATE_PR) { sys_wake_lock(FULL_WAKE_LOCK); } else { sys_wake_unlock(FULL_WAKE_LOCK); } #endif /* CONFIG_SYS_WAKELOCK */ } return false; #else static input_dev_data_t prev = { .point.x = 0, .point.y = 0, .state = INPUT_DEV_STATE_REL, .gesture = 0, }; input_dev_data_t curr; if (k_msgq_get(&pointer_scan_msgq, &curr, K_NO_WAIT) == 0) { prev = curr; } *data = prev; if (s_supported_gestures == 0) { pointer_gesture_detect(data); } return k_msgq_num_used_get(&pointer_scan_msgq) > 0; #endif } static void pointer_scan_enable(input_drv_t *drv, bool enable) { struct device *input_dev = (struct device *)device_get_binding("tpkey"); if (input_dev) { if (enable) input_dev_enable(input_dev); else input_dev_disable(input_dev); } } #endif /* CONFIG_INPUT_DEV_ACTS_TP_KEY */ static bool pointer_scan_read_fake(input_drv_t *drv, input_dev_data_t *data) { *data = (input_dev_data_t) { .point.x = 0, .point.y = 0, .state = INPUT_DEV_STATE_REL, .gesture_dir = 0, .scroll_dir = 0, }; return false; } int input_pointer_device_init(void) { input_drv_t input_drv; memset(&input_drv, 0, sizeof(input_drv)); input_drv.type = INPUT_DEV_TYPE_POINTER; input_drv.scroll_limit = POINTER_SCROLL_LIMIT; input_drv.gesture_limit = POINTER_GESTURE_LIMIT; input_drv.gesture_min_velocity = POINTER_GESTURE_MIN_VELOCITY; #ifdef CONFIG_INPUT_DEV_ACTS_TP_KEY input_drv.input_dev = (struct device *)device_get_binding("tpkey"); if (input_drv.input_dev) { struct input_capabilities cap; memset(&cap, 0, sizeof(cap)); input_dev_get_capabilities(input_drv.input_dev, &cap); s_supported_gestures = cap.pointer.supported_gestures; input_dev_register_notify(input_drv.input_dev, pointer_scan_callback); input_drv.read_cb = pointer_scan_read; input_drv.enable = pointer_scan_enable; } #endif /*CONFIG_INPUT_DEV_ACTS_TP_KEY*/ if (input_drv.input_dev == NULL) { os_printk("cannot found tpkey dev, fake one\n"); input_drv.read_cb = pointer_scan_read_fake; } input_driver_register(&input_drv); SYS_LOG_INF("init ok"); return 0; }