/**************************************************************************** * apps/graphics/input/generator/input_gen_event.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include "input_gen_internal.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define INPUT_GEN_DEFAULT_PRESSURE 42 #define INPUT_GEN_DEFAULT_PRESS_DURATION 50 /* ms */ #define INPUT_GEN_DEFAULT_HOLD_DURATION 5 /* ms */ #define INPUT_GEN_DEFAULT_CLICK_DURATION 100 /* ms */ #define INPUT_GEN_MAX_FINGERS 2 /**************************************************************************** * Private Types ****************************************************************************/ /* Structure to hold parameters for single finger operations, we can support * multiple fingers by using multiple instances of this structure. */ struct input_gen_single_finger_s { int16_t x1; int16_t y1; int16_t x2; int16_t y2; uint32_t press_duration; uint32_t move_duration; uint32_t hold_duration; }; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: input_gen_tick_get * * Description: * Get the current tick count in milliseconds. * * Returned Value: * The current tick count in milliseconds. * ****************************************************************************/ static uint32_t input_gen_tick_get(void) { struct timespec ts; uint32_t ms; clock_gettime(CLOCK_MONOTONIC, &ts); ms = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; return ms; } /**************************************************************************** * Name: input_gen_tick_elapsed * * Description: * Calculate the elapsed time in milliseconds since the last tick. * * Input Parameters: * act_time - The current tick count. * prev_tick - The previous tick count. * * Returned Value: * The elapsed time in milliseconds. * ****************************************************************************/ static uint32_t input_gen_tick_elapsed(uint32_t act_time, uint32_t prev_tick) { /* If there is no overflow in sys_time simple subtract */ if (act_time >= prev_tick) { prev_tick = act_time - prev_tick; } else { prev_tick = UINT32_MAX - prev_tick + 1; prev_tick += act_time; } return prev_tick; } /**************************************************************************** * Name: input_gen_single_finger * * Description: * Calculate the position of a single finger based on the elapsed time and * the parameters. * * Input Parameters: * point - The touch point structure to fill in. * finger - The parameters for the single finger operation. * elapsed - The elapsed time since the start of the operation. * * Returned Value: * True if the operation is finished, false otherwise. * ****************************************************************************/ static bool input_gen_single_finger(FAR struct touch_point_s *point, FAR const struct input_gen_single_finger_s *finger, uint32_t elapsed) { if (elapsed < finger->press_duration) { /* Press */ input_gen_fill_point(point, finger->x1, finger->y1, TOUCH_DOWN); return false; } elapsed -= finger->press_duration; if (elapsed < finger->move_duration) { int16_t x = ((int64_t)(finger->x2 - finger->x1) * elapsed) / finger->move_duration + finger->x1; int16_t y = ((int64_t)(finger->y2 - finger->y1) * elapsed) / finger->move_duration + finger->y1; input_gen_fill_point(point, x, y, TOUCH_MOVE); return false; } elapsed -= finger->move_duration; if (elapsed < finger->hold_duration) { /* Hold */ input_gen_fill_point(point, finger->x2, finger->y2, TOUCH_DOWN); return false; } /* Release */ input_gen_fill_point(point, finger->x2, finger->y2, TOUCH_UP); return true; } /**************************************************************************** * Name: input_gen_write_motion * * Description: * Write a motion event to the device. * * Input Parameters: * fd - The file descriptor of the device. * fingers - The parameters for the motion operation. * nfingers - The number of fingers. * elapsed - The elapsed time since the start of the operation. * * Returned Value: * Zero (OK) is returned on success. On failure, a negated errno value is * returned. * ****************************************************************************/ static int input_gen_write_motion(int fd, FAR const struct input_gen_single_finger_s *fingers, size_t nfingers, uint32_t elapsed) { size_t finished = 0; size_t i; int ret; union /* A union with enough space to make compiler / checker happy. */ { struct touch_sample_s sample; struct { uint8_t placeholder[offsetof(struct touch_sample_s, point)]; struct touch_point_s point[INPUT_GEN_MAX_FINGERS]; } points; } buffer; /* Check the number of fingers */ if (nfingers < 1 || nfingers > INPUT_GEN_MAX_FINGERS) { return -EINVAL; } /* Fill the touch sample structure */ buffer.sample.npoints = nfingers; for (i = 0; i < nfingers; i++) { FAR struct touch_point_s *point = &buffer.points.point[i]; point->id = i; if (input_gen_single_finger(point, &fingers[i], elapsed)) { finished++; } ginfo("Finger %zu: x = %d, y = %d, flags = %02X\n", i, point->x, point->y, point->flags); } /* Write the sample to the device */ ret = input_gen_utouch_write(fd, &buffer.sample); if (ret < 0) { return ret; } return finished == nfingers ? OK : -EAGAIN; } /**************************************************************************** * Name: input_gen_motion * * Description: * Perform a motion operation. * * Input Parameters: * ctx - The input generator context. * fingers - The parameters for the motion operation. * nfingers - The number of fingers. * * Returned Value: * Zero (OK) is returned on success. On failure, a negated errno value is * returned. * ****************************************************************************/ static int input_gen_motion(input_gen_ctx_t ctx, FAR const struct input_gen_single_finger_s *fingers, size_t nfingers) { FAR struct input_gen_dev_s *dev; uint32_t start; int ret; dev = input_gen_search_dev(ctx, INPUT_GEN_DEV_UTOUCH); if (dev == NULL) { return -ENODEV; } ret = input_gen_grab(dev); if (ret < 0) { return ret; } start = input_gen_tick_get(); do { uint32_t elapsed = input_gen_tick_elapsed(input_gen_tick_get(), start); ret = input_gen_write_motion(dev->fd, fingers, nfingers, elapsed); if (ret == -EAGAIN && usleep(8 * 1000) < 0) { nwarn("WARNING: Maybe interrupted by signal\n"); input_gen_ungrab(dev); return -errno; } } while (ret == -EAGAIN); input_gen_ungrab(dev); return ret; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: input_gen_tap * * Description: * Perform a tap operation. * * Input Parameters: * ctx - The input generator context. * x - The x coordinate. * y - The y coordinate. * * Returned Value: * Zero (OK) is returned on success. On failure, a negated errno value is * returned. * ****************************************************************************/ int input_gen_tap(input_gen_ctx_t ctx, int16_t x, int16_t y) { struct input_gen_single_finger_s finger = { .x1 = x, .y1 = y, .x2 = x, .y2 = y, .press_duration = INPUT_GEN_DEFAULT_PRESS_DURATION, .move_duration = 0, .hold_duration = 0, }; return input_gen_motion(ctx, &finger, 1); } /**************************************************************************** * Name: input_gen_drag / input_gen_swipe * * Description: * Perform a drag or swipe operation. * * Input Parameters: * ctx - The input generator context. * x1 - The start x coordinate. * y1 - The start y coordinate. * x2 - The end x coordinate. * y2 - The end y coordinate. * duration - The duration of the operation. * * Returned Value: * Zero (OK) is returned on success. On failure, a negated errno value is * returned. * ****************************************************************************/ int input_gen_drag(input_gen_ctx_t ctx, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t duration) { struct input_gen_single_finger_s finger = { .x1 = x1, .y1 = y1, .x2 = x2, .y2 = y2, .press_duration = INPUT_GEN_DEFAULT_PRESS_DURATION, .move_duration = duration, .hold_duration = INPUT_GEN_DEFAULT_HOLD_DURATION, }; return input_gen_motion(ctx, &finger, 1); } int input_gen_swipe(input_gen_ctx_t ctx, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t duration) { struct input_gen_single_finger_s finger = { .x1 = x1, .y1 = y1, .x2 = x2, .y2 = y2, .press_duration = 0, .move_duration = duration, .hold_duration = 0, }; return input_gen_motion(ctx, &finger, 1); } /**************************************************************************** * Name: input_gen_pinch * * Description: * Perform a pinch operation. * * Input Parameters: * ctx - The input generator context. * x1_start - The start x coordinate of the first finger. * y1_start - The start y coordinate of the first finger. * x2_start - The start x coordinate of the second finger. * y2_start - The start y coordinate of the second finger. * x1_end - The end x coordinate of the first finger. * y1_end - The end y coordinate of the first finger. * x2_end - The end x coordinate of the second finger. * y2_end - The end y coordinate of the second finger. * duration - The duration of the operation. * * Returned Value: * Zero (OK) is returned on success. On failure, a negated errno value is * returned. * ****************************************************************************/ int input_gen_pinch(input_gen_ctx_t ctx, int16_t x1_start, int16_t y1_start, int16_t x2_start, int16_t y2_start, int16_t x1_end, int16_t y1_end, int16_t x2_end, int16_t y2_end, uint32_t duration) { struct input_gen_single_finger_s fingers[2] = { { .x1 = x1_start, .y1 = y1_start, .x2 = x1_end, .y2 = y1_end, .press_duration = INPUT_GEN_DEFAULT_PRESS_DURATION, .move_duration = duration, .hold_duration = INPUT_GEN_DEFAULT_HOLD_DURATION, }, { .x1 = x2_start, .y1 = y2_start, .x2 = x2_end, .y2 = y2_end, .press_duration = INPUT_GEN_DEFAULT_PRESS_DURATION, .move_duration = duration, .hold_duration = INPUT_GEN_DEFAULT_HOLD_DURATION, }, }; return input_gen_motion(ctx, fingers, 2); } /**************************************************************************** * Name: input_gen_button_click / input_gen_button_longpress * * Description: * Perform a button click or long press operation. * * Input Parameters: * ctx - The input generator context. * mask - The button mask. * duration - The duration of the operation. * * Returned Value: * Zero (OK) is returned on success. On failure, a negated errno value is * returned. * ****************************************************************************/ int input_gen_button_click(input_gen_ctx_t ctx, btn_buttonset_t mask) { return input_gen_button_longpress(ctx, mask, INPUT_GEN_DEFAULT_CLICK_DURATION); } int input_gen_button_longpress(input_gen_ctx_t ctx, btn_buttonset_t mask, uint32_t duration) { FAR struct input_gen_dev_s *dev; int ret; dev = input_gen_search_dev(ctx, INPUT_GEN_DEV_UBUTTON); if (dev == NULL) { return -ENODEV; } ret = input_gen_grab(dev); if (ret < 0) { return ret; } ret = input_gen_ubutton_write(dev->fd, mask); if (ret < 0) { goto out; } usleep(duration * 1000); ret = input_gen_ubutton_write(dev->fd, 0); if (ret < 0) { goto out; } out: input_gen_ungrab(dev); return ret; } /**************************************************************************** * Name: input_gen_mouse_wheel * * Description: * Perform a mouse wheel operation. * * Input Parameters: * ctx - The input generator context. * wheel - The wheel value. * * Returned Value: * Zero (OK) is returned on success. On failure, a negated errno value is * returned. * ****************************************************************************/ #ifdef CONFIG_INPUT_MOUSE_WHEEL int input_gen_mouse_wheel(input_gen_ctx_t ctx, int16_t wheel) { FAR struct input_gen_dev_s *dev; dev = input_gen_search_dev(ctx, INPUT_GEN_DEV_UMOUSE); if (dev == NULL) { return -ENODEV; } return input_gen_umouse_write(dev->fd, wheel); } #endif /**************************************************************************** * Name: input_gen_fill_point * * Description: * Fill the touch point structure. * * Input Parameters: * point - The touch point structure. * x - The x coordinate. * y - The y coordinate. * flags - The TOUCH_DOWN, TOUCH_MOVE, TOUCH_UP flag. * ****************************************************************************/ void input_gen_fill_point(FAR struct touch_point_s *point, int16_t x, int16_t y, uint8_t flags) { point->x = x; point->y = y; point->h = 1; point->w = 1; if (flags & TOUCH_UP) { point->pressure = 0; point->flags = flags | TOUCH_ID_VALID; } else { point->pressure = INPUT_GEN_DEFAULT_PRESSURE; point->flags = flags | TOUCH_ID_VALID | TOUCH_POS_VALID | TOUCH_PRESSURE_VALID; } }